Errors use the OpenAI error shape on every endpoint except /v1/messages (see below):
{
"error": {
"message": "Insufficient wallet balance for this request. Top up your wallet and retry.",
"type": "insufficient_quota",
"code": "insufficient_balance",
"param": null
}
}codeis the stable machine-readable value. Branch oncode(and the HTTP status), not onmessage.typeis the OpenAI-compatible category.paramnames the offending field when there is one, otherwisenull.- Messages are fixed text. They never contain internal ids, stack traces or any part of your request.
- Every response, success or error, has an
x-request-idheader. Quote it to support. - When a retry makes sense later, a
Retry-Afterheader gives the number of seconds to wait.
Codes
| HTTP | code | type | When |
|---|---|---|---|
| 400 | invalid_request | invalid_request_error | The body failed validation, is not valid JSON or UTF-8, the content type is not JSON, n is not 1, or the request cannot fit the context window. param names the field when known. |
| 400 | context_length_exceeded | invalid_request_error | The input plus max_tokens exceeds the model's context window. |
| 401 | invalid_api_key | authentication_error | Missing, malformed, unknown, revoked or expired key. |
| 402 | insufficient_balance | insufficient_quota | The wallet cannot cover the hold for this request. The provider is never called and nothing is charged. |
| 403 | model_not_allowed | permission_error | The key is restricted to other models. |
| 403 | ip_not_allowed | permission_error | The key has an IP allowlist and your address is not on it. |
| 403 | org_suspended | permission_error | The organization is suspended. |
| 403 | org_blocked | permission_error | The organization has outstanding unpaid usage above the allowed limit. Top-ups do not clear it automatically: contact support with the request id. |
| 404 | model_not_found | invalid_request_error | The model does not exist or is not available. |
| 404 | not_found | invalid_request_error | Unknown endpoint. |
| 405 | method_not_allowed | invalid_request_error | Wrong HTTP method for the endpoint. |
| 408 | client_stalled | api_error | The client stopped reading a stream (reported inside the stream). |
| 409 | idempotency_conflict | invalid_request_error | The Idempotency-Key was used with a different request. |
| 409 | idempotency_in_progress | invalid_request_error | A request with this key is still running. |
| 409 | idempotency_replay_unavailable | invalid_request_error | The request with this key already completed, but its response can no longer be replayed. |
| 413 | request_too_large | invalid_request_error | The body is larger than 2 MiB. |
| 429 | rate_limited | rate_limit_error | Per-key or per-organization rate limit, too many concurrent requests, or too many failed authentication attempts. Has Retry-After. |
| 429 | key_cap_exceeded | rate_limit_error | The key reached its monthly spending cap. Has Retry-After (seconds until the next month). |
| 499 | client_closed_request | api_error | The client closed the request. |
| 500 | internal_error | api_error | An unexpected gateway error. |
| 502 | upstream_error | api_error | The model provider failed. The hold is released and you are not charged (before output started). |
| 503 | gateway_disabled | api_error | The API is temporarily switched off by the operator. Has Retry-After: 30. |
| 503 | no_upstream | api_error | No provider is available for this model. |
| 503 | model_unavailable | api_error | The model is temporarily unavailable. |
| 503 | service_unavailable | api_error | The service is shutting down or briefly unable to complete the request. Retry shortly. |
| 504 | upstream_timeout | api_error | The provider timed out (non-streaming requests time out after 120 seconds). You are not charged. |
403 org_blocked and 402 insufficient_balance are different. insufficient_balance means the wallet is too low for this request, so top up and retry. org_blocked means the organization has accumulated unpaid usage above a limit and needs a person to look at it.
/v1/messages error bodies
POST /v1/messages returns the Anthropic envelope, which has no code field. Use the HTTP status from the table above. See Messages for the error.type mapping.
{
"type": "error",
"error": { "type": "rate_limit_error", "message": "Rate limit exceeded." },
"request_id": "req_0123456789abcdef"
}Errors inside a stream
If a stream fails after the 200 was sent, the error arrives as the last event, as described in Streaming.
What to retry
| Status | Retry? |
|---|---|
| 400, 401, 402, 403, 404, 405, 413 | No. Fix the request, key, balance or permissions first. |
| 409 | Not as is. See Idempotency. |
| 429 | Yes, after the Retry-After interval. A key_cap_exceeded means waiting for the next month or raising the cap. |
| 500, 502, 503, 504 | Yes, with exponential backoff and jitter. |
More in Best practices.
curl -sS https://api.ticonai.com/v1/chat/completions \
-H "Authorization: Bearer $AIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "no-such-model", "messages": [{ "role": "user", "content": "hi" }] }'