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:

HeaderUse 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:

PropertyEnforced where
Model allowlistbefore the provider is called (403 model_not_allowed)
IP allowlist (CIDR)before the provider is called (403 ip_not_allowed)
Plan / model plan gatingbefore the provider is called (403 model_not_on_plan)
RPM rate limittoken bucket, checked on every request (429 rate_limit_exceeded)
Token quotas (daily/monthly)quota windows (429 quota_exceeded)
USD spend cappre-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-Id or X-Request-Id you send is ignored and overwritten.
  • Every response (success or error, JSON or audio or stream) carries the X-TF-Request-Id response header.
  • Every error body carries the same id as error.request_id.
  • Quote the X-TF-Request-Id in support requests — it is the correlation key we use across the whole product.

401 responses

CodeMeaningRecovery
missing_api_keyNo Authorization / x-api-key header on the request.Send the header.
invalid_api_keyKey hash not found.Re-copy the key; confirm the deployment.
inactive_api_keyKey resolved but deactivated.Re-enable in Settings → API keys.
expired_api_keyKey'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.