# Headers

> The request and response headers of the API, including request ids, idempotency and the rate limit headers.

This page lists every header the API reads or sends. Header names are case-insensitive. The examples use lowercase.

## Request headers

| Header | Required | Rule |
| --- | --- | --- |
| `authorization: Bearer <key>` | Yes, on every public route: `/v1/decide`, `/v1/models`, `/v1/key`, `/v1/usage` and `/v1/balance` | Your API key, starting with `dex_live_` or `dex_test_`. Missing or bad keys give 401. |
| `content-type: application/json` | Yes, on every request with a body | The body must be JSON in UTF-8. Anything else gives `400 unsupported_media_type`. |
| `idempotency-key` | No | On `POST /v1/decide` and the console's top-up route. 1 to 255 printable ASCII characters, without spaces. A malformed key gives `400 invalid_header`. See [Idempotency](/docs/reference/idempotency/). |
| `x-client-request-id` | No | Your own correlation id, on every public operation. 1 to 128 printable ASCII characters, without spaces. It is stored with the request metadata and echoed in the response. A malformed value gives `400 invalid_header` on every route. |
| `user-agent` | No | The SDKs send their name and version. Dex keeps the SDK name and version with the request metadata. |
| `x-dex-csrf` | Console only | The token the console receives at sign-in. Required on every console request that changes something. |

## Response headers

| Header | When | Rule |
| --- | --- | --- |
| `x-request-id` | Always | The request id: `req_` followed by a 26-character ULID. The same value is in the body's `id` and in `error.request_id`. |
| `x-client-request-id` | When you sent a valid one | Your correlation id, echoed on every response, errors included. |
| `idempotent-replayed: true` | On a replay | The idempotency key matched an earlier completed request. The body is the original response, and nothing is charged again. The `x-request-id` header names the replay itself. See [Idempotency](/docs/reference/idempotency/). |
| `ratelimit-policy` | Every authenticated API response | The limits that apply to this key. See [Rate limit headers](#rate-limit-headers). |
| `ratelimit` | Every authenticated API response | What is left of each limit, and when it resets. |
| `retry-after` | On 429, 503 and 409 `idempotency_in_progress` | Whole seconds to wait before retrying, from 1 to 60. |

## Rate limit headers

The rate limit headers use the structured-field form of the IETF httpapi rate limit draft. Each lists one entry per limit, separated by commas:

```text
ratelimit-policy: "rpm";q=300;w=60, "tpm";q=300000;w=60
ratelimit: "rpm";r=287;t=12, "tpm";r=291400;t=12
```

| Name or parameter | Meaning |
| --- | --- |
| `"rpm"` | Requests per minute. |
| `"tpm"` | Billable tokens per minute. |
| `q` | The quota: how many requests or tokens the window allows. |
| `w` | The window, in seconds. |
| `r` | What remains of the quota. |
| `t` | Seconds until the quota resets. |

Read the example as: this key may send 300 requests and 300,000 billable tokens per 60 seconds. It has 287 requests and 291,400 tokens left, and both reset in 12 seconds.

Use `ratelimit` to slow down before you hit a limit. When you do hit one, the 429 response names the exhausted limit in its error `code` and carries `retry-after`. See [Rate limits](/docs/reference/rate-limits/).

## Request ids

The gateway gives every request an id, including requests it rejects. The id is `req_` plus a ULID, so ids sort by time. You find it in the `x-request-id` header, in the body's `id` and in `error.request_id`.

Log it next to your own records. Support asks for the request id, never for the content of a request. If you send `x-client-request-id`, it is stored next to the request id in the request metadata and echoed back on the response, whichever public route you call and whether the call succeeds or fails. The SDKs take it on every method (`client_request_id` in Python, `clientRequestId` in TypeScript).
