> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chataigne.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authenticate Chataigne API requests with x-api-key, and keep public and admin surfaces strictly separated.

The Chataigne API authenticates every request with an API key passed in the
`x-api-key` header. There are two separate API surfaces, each with its own key
type. Keys are never interchangeable across surfaces.

| Surface                | Base path   | Key type                    | Key prefix  |
| ---------------------- | ----------- | --------------------------- | ----------- |
| Chataigne API (public) | `/v1`       | Location / organization key | `ch_org_`   |
| Admin API              | `/admin/v1` | Admin key                   | `ch_admin_` |

All requests go to the same host:

```
https://server.chataigne.ai
```

<Warning>
  API keys are secret credentials that act on behalf of your account. Treat
  them like passwords: never commit them to source control, never log them, and
  never embed them in browsers, mobile apps, or any client-side code. See
  [Keeping keys safe](#keeping-keys-safe).
</Warning>

## Authenticating a request

Send your key in the `x-api-key` header on every request. There is no
`Authorization: Bearer` scheme — only `x-api-key` is accepted.

<CodeGroup>
  ```bash curl theme={null}
  curl https://server.chataigne.ai/v1/locations \
    -H "x-api-key: ch_org_..."
  ```

  ```js Node.js theme={null}
  const response = await fetch("https://server.chataigne.ai/v1/locations", {
    headers: {
      "x-api-key": process.env.CHATAIGNE_API_KEY, // ch_org_...
    },
  });

  const locations = await response.json();
  ```
</CodeGroup>

<Note>
  Dashboard sessions are not API credentials. A logged-in dashboard session
  cannot be used to call `/v1` or `/admin/v1` — these surfaces only accept
  `x-api-key`.
</Note>

## The two surfaces

Chataigne exposes two independent API surfaces. Each is versioned by path
(`/v1`, `/admin/v1`) and accepts exactly one key type.

<CardGroup cols={2}>
  <Card title="Chataigne API" icon="store">
    Path `/v1`. Read and manage a single organization and its locations,
    settings, and special closings. Authenticated with **location /
    organization keys** (`ch_org_`).
  </Card>

  <Card title="Admin API" icon="shield-halved">
    Path `/admin/v1`. Provision and manage organizations and locations across
    accounts. Authenticated with **admin keys** (`ch_admin_`).
  </Card>
</CardGroup>

### Public API — `/v1`

The public Chataigne API is scoped to the organization (and its locations)
that the key belongs to. Use a `ch_org_` key.

```bash theme={null}
curl https://server.chataigne.ai/v1/organizations \
  -H "x-api-key: ch_org_..."
```

### Admin API — `/admin/v1`

The Admin API performs account-level operations such as creating organizations
and locations. Use a `ch_admin_` key.

```bash theme={null}
curl https://server.chataigne.ai/admin/v1/organizations \
  -H "x-api-key: ch_admin_..."
```

## Strict surface separation

Keys are bound to their surface. Sending a key to the wrong surface is rejected
— it is never silently downgraded or upgraded. This containment is enforced on
every request.

| Scenario                       | HTTP status | Error type             |
| ------------------------------ | ----------- | ---------------------- |
| Valid key, correct surface     | `200`       | —                      |
| Missing or malformed key       | `401`       | `authentication_error` |
| Wrong key type for the surface | `403`       | `authorization_error`  |

<Warning>
  An admin key sent to `/v1`, or an organization key sent to `/admin/v1`,
  returns **`403` `authorization_error`** — not `401`. A `401` means the key is
  absent or unrecognized; a `403` means the key is valid but not allowed on this
  surface. Use this distinction when debugging: `403` is almost always a
  surface/key-type mismatch.
</Warning>

### Missing key → 401

```bash theme={null}
curl https://server.chataigne.ai/v1/locations
```

```json theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "missing_api_key",
    "message": "No API key provided. Pass your key in the x-api-key header.",
    "request_id": "req_8f2c1a9d4e7b"
  }
}
```

### Wrong key type → 403

Sending an admin key to the public surface:

```bash theme={null}
curl https://server.chataigne.ai/v1/locations \
  -H "x-api-key: ch_admin_..."
```

```json theme={null}
{
  "error": {
    "type": "authorization_error",
    "code": "wrong_key_surface",
    "message": "An admin key cannot be used on /v1. Use a location or organization key (ch_org_).",
    "request_id": "req_3b6e0c2f5a81"
  }
}
```

The reverse — an organization key on `/admin/v1` — fails the same way:

```bash theme={null}
curl https://server.chataigne.ai/admin/v1/organizations \
  -H "x-api-key: ch_org_..."
```

```json theme={null}
{
  "error": {
    "type": "authorization_error",
    "code": "wrong_key_surface",
    "message": "An organization key cannot be used on /admin/v1. Use an admin key (ch_admin_).",
    "request_id": "req_d41f8a7c92e0"
  }
}
```

<Note>
  Every error response carries an `X-Request-Id` header, mirrored in the body as
  `error.request_id`. Include it when contacting support. See
  [Request IDs](/concepts/request-ids) and [Errors](/concepts/errors).
</Note>

## Key prefixes

Every key carries a prefix that identifies its surface at a glance. The prefix
is the only part of a key you should ever expose (for example, in logs or UI):
the secret portion that follows must stay confidential.

<ParamField path="ch_org_" type="prefix">
  Location / organization key. Authenticates the public Chataigne API
  (`/v1`). Scoped to a single organization and its locations.
</ParamField>

<ParamField path="ch_admin_" type="prefix">
  Admin key. Authenticates the Admin API (`/admin/v1`). Performs account-level
  provisioning across organizations and locations.
</ParamField>

<Tip>
  Use the prefix to fail fast in your own code. If a key destined for `/v1` does
  not start with `ch_org_`, you can reject it before making a network call —
  saving a round-trip and a `403`.
</Tip>

## Keeping keys safe

API keys grant full programmatic access to your data. A leaked `ch_admin_` key
in particular can manage organizations and locations across your account.

<Warning>
  **Never embed API keys in browsers, mobile apps, or any client-side code.**
  Anything shipped to a user's device is recoverable — view source, DevTools,
  and binary inspection all expose embedded secrets. Keys belong only on servers
  you control.
</Warning>

Recommended practices:

<CardGroup cols={2}>
  <Card title="Store in environment variables" icon="key">
    Load keys from environment variables or a secrets manager. Never hard-code
    them or commit them to version control.
  </Card>

  <Card title="Call from your backend" icon="server">
    Proxy all Chataigne API calls through your own server. The key never reaches
    the client.
  </Card>

  <Card title="Use least privilege" icon="lock">
    Reach for an `ch_org_` key whenever account-level access is not required.
    Reserve `ch_admin_` keys for provisioning workflows.
  </Card>

  <Card title="Rotate on exposure" icon="rotate">
    If a key is ever exposed — in a log, a screenshot, or a repo — rotate it
    immediately and audit recent activity.
  </Card>
</CardGroup>

A typical secure setup keeps the key server-side and exposes only the data your
client needs:

```js Node.js (server-side) theme={null}
// Runs on your server — the key never reaches the browser.
import express from "express";

const app = express();

app.get("/api/locations", async (_req, res) => {
  const response = await fetch("https://server.chataigne.ai/v1/locations", {
    headers: { "x-api-key": process.env.CHATAIGNE_API_KEY },
  });
  res.status(response.status).json(await response.json());
});
```

## Quick reference

```bash theme={null}
# Public API: list locations (organization key)
curl https://server.chataigne.ai/v1/locations \
  -H "x-api-key: ch_org_..."

# Public API: retrieve one organization (organization key)
curl https://server.chataigne.ai/v1/organizations/org_... \
  -H "x-api-key: ch_org_..."

# Admin API: list organizations (admin key)
curl https://server.chataigne.ai/admin/v1/organizations \
  -H "x-api-key: ch_admin_..."
```

<ResponseField name="x-api-key" type="header" required>
  Your API key. Use a `ch_org_` key for `/v1` and a `ch_admin_` key for
  `/admin/v1`. Required on every request.
</ResponseField>

## Next steps

<CardGroup cols={2}>
  <Card title="Errors" icon="triangle-exclamation" href="/concepts/errors">
    Error types, status codes, and response shape.
  </Card>

  <Card title="Request IDs" icon="fingerprint" href="/concepts/request-ids">
    Trace any request with `X-Request-Id`.
  </Card>

  <Card title="Rate limits" icon="gauge-high" href="/concepts/rate-limits">
    Per-key, per-surface limits and headers.
  </Card>

  <Card title="Versioning" icon="code-branch" href="/concepts/versioning">
    Path-based major versions and breaking-change policy.
  </Card>
</CardGroup>
