OpenAI & Anthropic Compatibility
The gateway's two wire dialects — same underlying contract, different shapes.
The gateway natively speaks the OpenAI schema. The Anthropic Messages
dialect is served by a translating proxy (/v1/messages), so Claude SDKs work
unchanged against the same keys, models, limits, and ledger. This page is the
side-by-side for developers with an existing integration in either dialect.
Which dialect do I need?
| If your code uses… | Send requests to | Auth header |
|---|---|---|
| The OpenAI SDK (or anything OpenAI-dialect: LangChain, Vercel AI SDK, …) | https://api.<domain>/v1/… | Authorization: Bearer <key> |
| The Anthropic SDK / Claude Code | https://api.<domain>/v1/messages | x-api-key: <key> (Bearer also accepted) |
One API key works across both surfaces — the key, its model allowlist, plan, rate limits, and spend caps are enforced identically regardless of dialect.
What is identical (the contract)
Regardless of dialect:
modelechoes verbatim — the responsemodelfield is exactly the alias you sent, even when failover changed the serving provider.provider_metadatais always present on successful bodies, carryingprovider(who actually served the request) andactual_model(the provider's internal model id).- Every error carries a server-minted
request_id— quote it in support requests; it is the correlation id across all logs. - The same validation, policy, and billing path applies: model allowlist, rate limits, and the prepaid credit reservation run before any provider is called.
- The same
X-TF-*side-channel headers accompany every response (see Streaming and Errors).
What differs (the shapes)
| OpenAI dialect | Anthropic dialect | |
|---|---|---|
| Path prefix | /v1/* (except /v1/messages) | /v1/messages (+ /v1/messages/count_tokens) |
| Auth header | Authorization: Bearer <key> | x-api-key: <key>; Authorization: Bearer also accepted |
| Error envelope | {"error": {...}, "request_id": "…"} | {"type": "error", "error": {...}, "request_id": "…"} — request_id is a top-level sibling, no code/param |
| Streaming events | data: {"choices":[…]} chunks, terminated by data: [DONE] | Native message_start / content_block_* / message_delta / message_stop sequence |
| Usage block | usage{prompt_tokens, completion_tokens, total_tokens} | usage{input_tokens, output_tokens} (+ prompt-cache keys) |
Worked example — same request, both dialects
OpenAI dialect (Authorization: Bearer):
curl https://api.<domain>/v1/chat/completions \
-H "Authorization: Bearer $TOKENFACTORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet",
"messages": [{ "role": "user", "content": "Hello!" }],
"max_tokens": 64
}'Anthropic dialect (x-api-key):
curl https://api.<domain>/v1/messages \
-H "x-api-key: $TOKENFACTORY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "Hello!" }]
}'Both hit the same model alias, consume the same wallet, and return
provider_metadata. The OpenAI response wraps text in
choices[0].message.content; the Anthropic response uses content[].text
with a stop_reason.
Migrating an existing client
- From a provider direct to the gateway: change the base URL and swap the API key — nothing else. See Quickstart for the two-step recipe.
- Between dialects: path prefix, auth header, and response shape change (table above). Model names are shared — the same curated alias works on both surfaces (Models & Aliases).