# Authentication

Every API request carries a bearer key:

```
Authorization: Bearer sk-om-v1-...
```

Keys are created in the dashboard (browser session only; keys cannot be
managed with another API key). The secret is shown exactly once at creation;
only a hash is stored. Revoking takes effect immediately.

## Per-key limits

- **Rate limit** — requests per minute, 300 by default, enforced as an exact
  sliding window. Exceeding it returns 429 with a `Retry-After` header.
- **Spend limit** — optional budget in USD (`spendLimitUsd`) per
  `spendLimitInterval` of `daily`, `weekly` or `monthly`; omit the
  interval for a lifetime budget. Settled charges plus active holds count
  against it. When the budget is reached, requests fail with
  403 `key_spend_limit_exceeded` until the window resets.
- **Cost cap** — optional maximum cost per request
  (`maxCostPerRequestUsd`). A request whose worst case exceeds the cap is
  refused with 403 `request_cost_limit_exceeded` before anything is spent.
- **Expiry** — optional `expiresAt` timestamp; an expired key stops
  authenticating.
- **Model allowlist** — optionally restrict a key to specific models; an
  empty list means every model.

Keys spend the account's shared credit balance. There is no per-key balance:
limits are the tool for containing an individual key's blast radius.

## Scopes

A key's scopes limit which endpoint families it may call. Valid values:
`CHAT`, `COMPLETIONS`, `RESPONSES`, `EMBEDDINGS`, `DECISIONS`, `IMAGES`,
`VIDEOS`, `AUDIO_SPEECH`, `AUDIO_TRANSCRIPTIONS`,
`AUDIO_GENERATIONS`, `MUSIC`, `WORKFLOWS`, `BILLING_READ`, or `"*"` for everything.
Calling outside a key's scopes returns 403 `insufficient_scope`.

## Editing keys

Name, spend limit, cost cap and expiry are editable after creation
(dashboard → API keys → Edit; `PATCH /keys/:id` with the session). Patch
semantics: an omitted field is unchanged, an explicit `null` clears it.
Scopes, the model allowlist and the rate limit are fixed at creation; mint a
new key to change them.
