Error codes and next steps

Look up a status code the Gateway returned to see what it means, what to check first, and what to do next.

Status codes#

Jump to: 400 · 401 · 402 · 403 · 429 · 502 · 503 · 5xx

Include the request_id when you contact support

Every error response carries a request_id. Include it when you contact support so we can find the request.

StatusWhat it meansCheck firstWhat to do
400Malformed requestA missing field, invalid JSON, or something the format does not supportFix the request against the endpoint's parameter table and send it again
401Invalid keyWhether a key was sent, whether it starts with atp-, and whether it is disabled or expiredCheck or recreate it under "API Keys"; for header placement, see Authentication
402Credits are used upAvailable credits under "Usage" in the ConsoleAdd credits under "Billing"; for a team organization, also allocate credits under "Resources"
403The model is not enabled for this projectThe model IDs returned by GET /v1/modelsUse a model from that list, or add the model to the project under "Resources"
429Rate limit, quota, or provider cooldownThe Retry-After response headerWait for Retry-After, then retry
502Provider connection failed or timed out—Safe to retry right away
503Every provider for this model is temporarily unavailableRetry-After: 60Retry after 60 seconds
5xxProvider or Gateway errorThe request_id in the responseLook up the request ID under "Request logs" in the Console; include it when you contact support

See where a request stops#

Choose a scenario to see where the request stops and what the response looks like.

Request path through ATPPick a scenario to see where the request stops and what comes back.
Scenario
Response

200 OKReached Log & billing

Headers
x-ratelimit-limit-requests: …
x-ratelimit-remaining-requests: …
x-ratelimit-reset-requests: …

The body is the provider's response in your SDK's format. Rate-limit headers tell you how much room is left.

Log & billing — Input and output tokens are metered and charged in credits against the project's balance; the call shows up in the console's request logs.

Chat completion (curl)This check has no matching line in the request.
curl https://api.atptoken.ai/v1/chat/completions \
  -H "Authorization: Bearer atp-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model from GET /v1/models>",
    "messages": [{"role": "user", "content": "hi"}]
  }'
Text version
Request path through ATP
StepCheckStops withResponse
1. ClientSends a project key——
2. Key checkValid, active key401 Unauthorized{"message":"API key has been revoked or does not exist.","error":"token_revoked"}
3. Model allowlistModel enabled for the project403 Forbidden{"error":{"message":"model not available for this project","type":"permission_denied","request_id":"..."}}
4. CreditsProject balance left402 Payment RequiredAn error body in your SDK's error format: the wallet or credit pool is exhausted. Top up to resume; retrying won't help.
5. Rate limitWithin limits429 Too Many RequestsAn error body in your SDK's error format: a rate limit, quota or provider cooldown. Back off and retry; honor Retry-After if present.
6. ProviderRouted with failover——
7. Log & billingMetered in credits200 OKx-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests — The body is the provider's response in your SDK's format. Rate-limit headers tell you how much room is left.

200 with empty content#

A request can return 200 OK with an empty message — no error, just no text. This is almost always driven by request parameters, not a failure. The most common cause is a max_tokens that is too low for a reasoning (extended-thinking) model: the entire budget is consumed by internal reasoning before any visible output is produced, so the content comes back empty.

On this platform that request typically reports zero token usage and deducts no credits — an empty 200 with an empty usage object is the signature of this case, not a billing bug. Fix it by raising max_tokens so it covers the model's thinking budget plus your expected output, or turn extended thinking off. Always check finish_reason / stop_reason and usage before assuming text exists.

Was this page helpful?