# OpenAI HTTP headers — atlas **Status:** documented headers `DOCUMENTED`; every header marked *observed* was seen in our own responses on 2026-09-18 (`LIVE_VERIFIED`); `openai-project`, `x-should-retry`, `retry-after-ms`, `CF-RAY` are `LIVE_DISCOVERED` (observed / SDK source, not on the docs pages). `Idempotency-Key` is **not** an OpenAI header (`UNVERIFIED`/absent from spec). **Sources:** [API overview → Request headers / Debugging requests](https://developers.openai.com/api/reference/overview#debugging-requests) · [Rate limits → headers](https://developers.openai.com/api/docs/guides/rate-limits#rate-limits-in-headers) · [Webhooks guide](https://developers.openai.com/api/docs/guides/webhooks) · [Realtime WebSocket guide](https://developers.openai.com/api/docs/guides/realtime-conversations) · SDK sources (`openai/_base_client.py`, `openai/client.js`). **Last verified:** 2026-09-18. Machine-readable: `generated/fragments/headers/openai-headers.json` (32 records). ## Request headers | Header | Required | Values / rules | Verified | |---|---|---|---| | `Authorization` | yes | `Bearer ` | observed (401 shapes when wrong/missing) | | `Content-Type` | yes (bodies) | `application/json`; `multipart/form-data` for uploads; `application/sdp` (Realtime WebRTC) | observed: `text/plain` → `400 unsupported_content_type` | | `OpenAI-Organization` | no | org id; must match the key's org | observed: mismatch → `401 mismatched_organization` | | `OpenAI-Project` | no | project id (legacy user keys) | observed: unknown → `401 invalid_project` | | `OpenAI-Beta` | per surface | `assistants=v2` (legacy Assistants), `agents=v1` (Agents API), `chatkit_beta=v1`, `responses_multi_agent=v1`, `workspace_agent_runs=v1`, `realtime=v1` (legacy Realtime beta) | documented; `invalid_beta` 400 observed by another agent | | `X-Client-Request-Id` | no | your correlation id, ASCII, ≤ 512 chars, unique | observed: non-ASCII → `400`; accepted otherwise, not echoed | | `Accept` | no | `text/event-stream` implied by `stream: true` | documented | | `User-Agent` + `X-Stainless-*` | SDK | telemetry (`X-Stainless-Lang`, `-Package-Version`, `-OS`, `-Arch`, `-Runtime`, `-Runtime-Version`, `X-Stainless-Retry-Count`, `X-Stainless-Timeout`) | SDK source | | `Idempotency-Key` | — | **not supported/documented**; dedupe yourself (`metadata`, Batch `custom_id`, webhook `webhook-id`) | absent from spec | | Size budget | — | all headers < 64 KiB; custom header values ≤ 60 KiB total | documented | Realtime WebSocket: server side `Authorization: Bearer …`; browsers pass the ephemeral key as subprotocol `realtime, openai-insecure-api-key.`; legacy beta also `OpenAI-Beta: realtime=v1`. ## Response headers | Header | Meaning | Observed value (2026-09-18) | |---|---|---| | `x-request-id` | request id for support; SDK `response._request_id` / `_request_id` | `req_b02412ebc5604692b13b994c52e5e674` on chat/completions, responses, audit_logs; UUID form (`bc452ff1-…`) on models, webhook_endpoints, organization/*; **absent** on edge 404 (unknown URL) | | `openai-processing-ms` | server processing time | `2` … `582` | | `openai-version` | REST API version | `2020-10-01` (also on 4xx) | | `openai-organization` | billed org | present on model calls, admin 403s; absent on 401s and `GET /v1/models/{id}` | | `openai-project` | project of the key (**not documented**) | `proj_…` alongside `openai-organization` | | `x-ratelimit-limit-requests` / `-tokens` | RPM / TPM ceilings for the model | `30000` / `150000000` (gpt-4.1-nano) | | `x-ratelimit-remaining-requests` / `-tokens` | remaining in window | `29999` / `149999995` | | `x-ratelimit-reset-requests` / `-tokens` | Go duration until reset | `2ms` / `0s` (docs: `1s`, `6m0s`) | | `x-ratelimit-limit-project-tokens`, `-remaining-project-tokens`, `-reset-project-tokens` | only when a project token limit applies | not present on our project | | `Retry-After` | seconds to wait; on 429 (temporary limit / `slow_down`) and 503 (`server_is_overloaded`); never for quota/billing | not triggered | | `retry-after-ms` | ms variant parsed by SDKs first | SDK source | | `x-should-retry` | `true`/`false` overrides SDK retry decision | SDK source | | `CF-RAY` | Cloudflare trace id (`…-YUL` = Montréal edge) | on every response incl. bodyless 404 | | `Content-Type` | `application/json`; `text/event-stream` for streams | observed | | `Location` | Realtime WebRTC `POST /v1/realtime/calls` → `/v1/realtime/calls/{call_id}` | documented | Rate-limit headers appear on model endpoints even when the request fails validation (seen on the `400 invalid_value` chat/completions probe) — a rejected request still consumed a request slot (`remaining-requests: 29999`). ## Webhook request headers (OpenAI → your server) | Header | Value | |---|---| | `webhook-id` | `wh_…` unique delivery id (dedupe key; part of the signed string) | | `webhook-timestamp` | unix seconds; SDK tolerance ±300 s | | `webhook-signature` | `v1,` list, space separated | | `user-agent` | `OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)` | | `content-type` | `application/json` | ## Error-response header behaviour (observed) | Status | `x-request-id` | `openai-organization`/`-project` | rate-limit headers | |---|---|---|---| | 400 validation on model endpoint | yes (`req_…`) | yes | yes | | 401 auth failures | yes (UUID) | no | no | | 403 admin scope (`/organization/*`) | yes (UUID) | yes (except certificates) | no | | 404 unknown URL | **no** (only `CF-RAY`) | no | no | | 405 wrong method | yes | — | no |