# Authentication and API keys

Use a customer API key from your backend. The same account owns its keys, allocation, entitlement and usage.

## Send exactly one credential header

Preferred:

```http
Authorization: Bearer <key>
Content-Type: application/json
```

Alternative:

```http
X-API-Key: <key>
Content-Type: application/json
```

The examples show header syntax; replace the key through a secret manager or environment variable. Never send both key headers. The Authorization value must use the exact Bearer scheme shown. Do not put a key in a query string, public repository, browser JavaScript, mobile bundle or downloadable configuration.

Header names are case-insensitive. Credential values are secrets and must be preserved exactly. Leading/trailing copy errors or a truncated key can cause a 401.

## Create and store a key

Sign in to [Account](/account/) and create a customer API key. Save the complete key when it is displayed; subsequent key listings contain its prefix and metadata, not the full value.

The account can hold up to **ten active customer/extension keys**. Server-managed browser metering keys do not occupy a customer slot or appear in the customer key list. A new key shares the existing account authority and allowance.

Registration does not automatically issue a customer key. A website session and an API key are different credentials.

## Shared inference-only keys

A shared inference-only key starts with `sk_inf_`. It is issued by an operator to a dedicated identity of its own; it is not created in Account and is not one of your account's customer keys. It can call only `POST /v1/chat/completions`, `POST /v1/answers` and `GET /v1/models`; every other route answers HTTP 403 `inference_scope_denied`. Its stored lifetime token cap and expiry are described under [Limits and billing](limits-and-billing.md#shared-inference-only-keys). A request at or after its expiry is refused with HTTP 401 `unauthorized`.

## Separate environments

Create separate keys for development, staging and production where the account's key limit permits. Store each key only in the deployment that needs it. Monitor by key prefix, and keep the complete value out of logs, traces, crash reports and support requests.

Separate keys still share account limits. Use separately provisioned accounts or a separately agreed service arrangement if you need stronger organisational isolation or independently managed quotas.

## Rotate a key

1. Create a replacement key in Account.
2. Store it in the relevant secret manager.
3. Update the service and check an authenticated request.
4. Revoke the previous key in Account.
5. Confirm that remaining services have switched.

Rotation is this replacement-and-revocation workflow; the reviewed customer API does not provide a dedicated rotation endpoint or a documented grace-period promise.

If a key may have leaked, revoke it and replace it. Review unexpected usage and remove the exposed value from the affected configuration. Do not send the old or new key to support.

## Key-management API boundary

The website uses GET/POST /v1/account/keys and DELETE /v1/account/keys/{prefix} to manage keys. These are **session-authorised account controls**. A customer API key is not sufficient to administer or mint other keys.

Browser session mutations also require the service's CSRF protections. Use Account for the normal key-management flow; do not transplant browser cookies into a server SDK.

## Authentication failures

| Symptom | Action |
| --- | --- |
| Missing API key | Check the environment in the actual server process and send one credential header. |
| Invalid API key | Check copying, revocation/expiry and the account; create a replacement if needed. |
| Both headers supplied | Remove one. Do not rely on header precedence. |
| Authorization scheme rejected | Use Authorization: Bearer followed by the key, or use X-API-Key. |
| Cookie works in a website but SDK fails | Supply a customer API key; the transcript/tool chat path does not accept a session alone. |
| Origin or CSRF failure | Keep server calls free of browser session cookies; use the supported account UI for browser controls. |
| 403 inference_scope_denied | A shared inference-only key called a route outside its scope. Use only answers, chat completions and model discovery with it. |

A request can fail model or body validation before authentication. An unsupported_model response does not establish that a supplied key is valid.

See [Production guidance](production.md) for request IDs, retries and operational logging.
