Authentication
API keys, auth headers, key hierarchy, request ids, and how auth failures are reported.
Auth headers
Two headers are accepted on every path; read order is authorization first,
then x-api-key:
| Header | Use with |
|---|---|
Authorization: Bearer <api-key> | OpenAI SDKs (default) |
x-api-key: <api-key> | Anthropic SDKs (default) |
curl https://api.<domain>/v1/chat/completions \
-H "Authorization: Bearer $TOKENFACTORY_API_KEY" \
...curl https://api.<domain>/v1/messages \
-H "x-api-key: $TOKENFACTORY_API_KEY" \
...Key hierarchy and scope
Keys are hierarchical: Organisation → Project → API key. A key carries:
| Property | Enforced where |
|---|---|
| Model allowlist | before the provider is called (403 model_not_allowed) |
| IP allowlist (CIDR) | before the provider is called (403 ip_not_allowed) |
| Plan / model plan gating | before the provider is called (403 model_not_on_plan) |
| RPM rate limit | token bucket, checked on every request (429 rate_limit_exceeded) |
| Token quotas (daily/monthly) | quota windows (429 quota_exceeded) |
| USD spend cap | pre-flight (402 key_spend_cap_reached) |
A project-scoped key whose project is disabled returns 403 project_disabled.
Any key of a suspended organization returns 403 organization_suspended until the organization is resumed.
Per-key and project USD spend caps surface as 402 — see
Billing.
All of this is decided by the gateway's policy engine before any provider is called — a denied request never reaches a provider, and is never billed.
Request ids
- Request ids are minted server-side. Any
X-TF-Request-IdorX-Request-Idyou send is ignored and overwritten. - Every response (success or error, JSON or audio or stream) carries the
X-TF-Request-Idresponse header. - Every error body carries the same id as
error.request_id. - Quote the
X-TF-Request-Idin support requests — it is the correlation key we use across the whole product.
401 responses
| Code | Meaning | Recovery |
|---|---|---|
missing_api_key | No Authorization / x-api-key header on the request. | Send the header. |
invalid_api_key | Key hash not found. | Re-copy the key; confirm the deployment. |
inactive_api_key | Key resolved but deactivated. | Re-enable in Settings → API keys. |
expired_api_key | Key's expiry has passed. | Create a new key. |
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null,
"request_id": "req_01J8EXAMPLE"
}
}When a provider credential fails
If a provider rejects our credential, you never see a 401/403 for it — you cannot fix that, we can. Instead of a confusing provider auth failure you get a clean, actionable error:
502 provider_unavailable
"a provider rejected the platform credential"with the provider's own text withheld. See Errors for the full status-mapping table.