Errors & limits
The Gateway API returns errors in an OpenAI-compatible shape:
{
"error": {
"message": "Invalid API key.",
"type": "authentication_error",
"code": "invalid_api_key"
},
"request_id": "req_accly_1779290000000_0123456789abcdef"
}Use error.code for programmatic handling. Error messages are written for humans and can change. Include request_id when contacting support; the same value is returned in X-Request-ID and X-Accly-Request-ID response headers.
Authentication errors
| HTTP status | Code | Meaning |
|---|---|---|
| 401 | missing_api_key | API key is missing or empty |
| 401 | invalid_authorization_header | Authorization header is malformed or does not use the Bearer scheme |
| 401 | invalid_api_key | API key is revoked, expired, or invalid |
| 401 | missing_session | Accly app session cookie is missing or empty |
| 401 | invalid_session | Accly app session cookie is invalid or expired |
| 402 | subscription_suspended | Renewal payment failed and Accly suspended model access |
| 403 | account_restricted | Account is currently restricted |
| 429 | auth_rate_limit_exceeded | Too many failed authentication attempts from the same source |
Example:
{
"error": {
"message": "API key is required.",
"type": "authentication_error",
"code": "missing_api_key"
},
"request_id": "req_accly_1779290000000_0123456789abcdef"
}Request errors
| HTTP status | Code | Meaning |
|---|---|---|
| 400 | invalid_body | Request body could not be read |
| 400 | invalid_json | Request body could not be parsed |
| 400 | missing_model | model is required |
| 400 | missing_messages | messages is required and must not be empty |
| 400 | vision_not_supported | Request included vision input for a model without vision support |
| 400 | context_too_large | Input exceeded Accly token policy |
| 403 | model_not_allowed | Your key group or plan cannot use that endpoint or model tier |
| 404 | model_not_found | Model ID was not found |
| 404 | model_route_not_found | No route exists for the requested model/category/mode |
| 405 | method_not_allowed | The endpoint only accepts POST |
| 500 | missing_user / missing_plan | Request could not be associated with a valid account or plan |
Limit errors
Limit errors use type: "rate_limit_error" and a more specific code.
| HTTP status | Code | Meaning |
|---|---|---|
| 429 | rate_limit_exceeded | RPM limit reached |
| 429 | daily_limit_exceeded | Daily request limit reached |
| 429 | budget_exceeded | Daily Balanced or Premium budget is exhausted |
| 429 | free_balance_exhausted | Free one-time model balance is exhausted |
| 429 | concurrency_queue_timeout | Too many active requests; queued request timed out |
| 429 | auth_rate_limit_exceeded | Failed authentication attempts exceeded the gateway auth-abuse guard |
Daily budgets and daily request limits reset at midnight UTC. RPM resets on the short rolling minute window.
Provider and availability errors
The gateway maps provider failures into Accly error codes where possible.
| Typical status | Code | Meaning |
|---|---|---|
| 400 | context_length_exceeded | Provider or model context limit was exceeded |
| 400 | content_policy_violation | Provider rejected content for policy reasons |
| 429 | upstream_rate_limit | Upstream provider or route is rate limited |
| 502 | provider_error | Provider request failed |
| 502 | provider_bad_gateway | Provider returned a bad gateway-style error |
| 503 | no_available_provider | No available provider route could serve the request |
| 503 | provider_unavailable | Provider unavailable |
| 503 | provider_auth_invalid | Provider route auth failed |
| 503 | provider_balance_exhausted | Provider route balance unavailable |
| 504 | provider_timeout | Upstream provider timed out |
Provider and availability errors can be temporary. If the request is safe to retry, wait briefly and try again. If the error keeps happening, choose another supported model or contact support with the request ID.
Handling errors in code
const errorBody = await response.json().catch(() => null)
const code = errorBody?.error?.code
if (code === 'rate_limit_exceeded') {
// Wait and retry later.
}
if (code === 'budget_exceeded' || code === 'free_balance_exhausted') {
// Stop retrying until the user changes plan or the daily reset happens.
}
if (code === 'model_not_allowed') {
// Ask the user to choose a model allowed by their plan.
}