API error codes: what each one means
401 through 503, which of them are worth retrying, and how to tell a gateway error from one the upstream produced.
Errors the gateway raises before your request leaves
Credential problems are 401: a missing or unrecognised key, a revoked key, an expired key. The body is a flat {"error": "..."} with the reason as a string — "unauthorized", "api key revoked", "api key expired". None of these clear on retry.
Funding problems split by kind. A key that has burned through its own per-key quota is 402 "api key quota exceeded". An account with no spendable wallet left is 403 with a message naming which balance is empty. Claude ids additionally require a recharge balance of at least $2.00 and refuse other wallets, returning 402 with code claude_minimum_balance.
A request the catalog does not recognise is 400. The body names the id: "model not allowed: <id>". Where an id has been retired in favour of a dedicated lane the message names the replacement — "model not allowed: claude-haiku-4-5. Use stable-claude-haiku-4-5 instead." — because the replacement is priced differently and switching to it has to be your call, not a silent substitution. An empty model field is 400 "model is required".
curl -sS -o /tmp/body.json -w '%{http_code}\n' \
-D /tmp/headers.txt \
https://token-share.app/v1/messages \
-H "x-api-key: $TOKEN_SHARE_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 64,
"messages": [{"role": "user", "content": "ping"}]
}'
grep -i '^x-token-share-request-id' /tmp/headers.txt
cat /tmp/body.jsonCapacity and availability: 429 and 503
Two models — claude-sonnet-5 and gpt-5.6-luna — carry a per-model concurrency cap. Exceeding it returns 429 with code model_capacity_exceeded and a Retry-After: 1 header, or code model_queue_timeout when the request waited in the lane's queue and the wait ran out. Both clear on their own; back off and retry.
On a stable-* id, 429 arrives as stable_channel_rate_limited or stable_channel_busy, and 503 as stable_channel_unavailable. A dedicated lane does not fall back to the shared pool, so a failure there is returned as a failure rather than absorbed — that is the trade-off the lane is built around.
A 503 with code no_cluster_capacity means no machine could serve that provider at that moment. A 503 "key lookup temporarily unavailable, please retry" is different in kind: the key store could not be reached, so the gateway declined to guess rather than reject a valid key. Both are worth retrying.
When 502 means the upstream, not you
The gateway returns 502 when every provider it tried failed. On /v1/messages the body is Anthropic-shaped — {"type":"error","error":{"type":"api_error","code":"all_providers_failed",...}} — and on the OpenAI-shaped routes it is {"error":{"type":"server_error","code":"all_providers_failed",...}}. Both carry request_id at the top level.
Two narrower 502s exist. "upstream returned an empty body" means a provider promised a body and delivered nothing, which the proxy catches before your client sees an unparseable success. And a provider that answers 200 with an error envelope inside has its status corrected to 502 while its own body is forwarded verbatim, so the provider's own explanation reaches you.
Statuses the gateway does not synthesize are relayed with the provider's own body and status. If you get a 400 that is not one of the shapes above, it came from the model provider and describes your payload — a malformed tool schema, an unsupported parameter, a max_tokens above the model's ceiling.