Error Codes

API error responses and solutions

The Onysoft API returns standard HTTP status codes and detailed error messages.

HTTP Status Codes

Code Meaning Description
200OKRequest completed successfully
202AcceptedAsynchronous task created (video/image/music)
400Bad RequestInvalid request format or missing parameter
401UnauthorizedInvalid or missing API key
402Payment RequiredInsufficient balance: the balance does not cover the estimated maximum cost of the request (see Balance pre-check)
403ForbiddenProject suspended, model blocked or access denied
404Not FoundEndpoint or record not found (wrong path, unknown model detail, usage record or task id)
413Payload Too LargeRequest size too large (max 10MB — for base64 images)
422Unprocessable EntityMissing or invalid parameters (validation_error — e.g. model/messages missing)
429Too Many RequestsRate limit or token limit exceeded
500Internal Server ErrorServer error
502Bad GatewayInvalid response from the upstream provider or from your device (upstream_error, node_error); retry shortly
503Service UnavailableService temporarily unavailable: the model is busy (service_unavailable) or no device is ready (node_unavailable, node_busy). Follow the Retry-After and X-Should-Retry headers

Error Response Format

JSON
{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Insufficient balance. Add funds at https://api.onysoft.com/dashboard/billing",
    "type": "insufficient_quota",
    "param": null
  }
}

The error body is compatible with the OpenAI error format: SDKs read error.message, error.code, error.type and error.param. type follows the HTTP status: 401 authentication_error, 402 insufficient_quota, 403 permission_error, 404 not_found_error, 429 rate_limit_error, 5xx server_error, otherwise invalid_request_error. param names the field the error refers to (for validation errors the first invalid field; all of them are listed in fields); it is null or empty when no specific field applies. For backward compatibility "success": false and endpoint-specific extra fields (e.g. retry_after, fields, required) are kept. This format applies to /v1/chat/completions and the other endpoints; the formats of /v1/responses and the Anthropic endpoints are in the table below.

Error Format by Endpoint

EndpointError body
/v1/chat/completions, other endpointsThe format above: {"success": false, "error": {"code", "message", "type", "param"}}
/v1/responsesOpenAI format: {"error": {"message", "type", "param", "code"}}; no success field
/v1/messages, /v1/messages/count_tokens, /v1/models with the anthropic-version headerAnthropic format: {"type": "error", "error": {"type", "message"}}; types and mapping in the Anthropic Messages API section

Balance Pre-check (402)

402 is not returned only when the balance reaches zero. Before every paid request an estimated maximum cost is computed: input estimate + output reservation; the output reservation is max_tokens (or max_completion_tokens / max_output_tokens on Responses) if sent, otherwise the model's maximum output tokens. A 20% safety buffer is added; if your balance is below that, the request returns 402 insufficient_balance without ever reaching the model. The required and available fields of the error body show the required and the available amount. You are always charged for actual usage; the pre-check is only a sufficiency check. Free models are not pre-checked. The threshold depends on the model price and the current exchange rate.

For coding assistants this threshold can be high: Codex and Cursor send no maximum output limit and Claude Code asks for 64,000–128,000 output tokens. If you get 402 although your balance looks sufficient, lower max_tokens / max_output_tokens; in Claude Code use CLAUDE_CODE_MAX_OUTPUT_TOKENS.

Error Message Language

The message field of an error body is produced in English or Turkish; code, type, param, the HTTP status and the extra fields (retry_after, fields …) are language-independent and never change. Order of precedence: 1) the ?lang=tr / ?lang=en query parameter. 2) the Accept-Language header — when sent, it always wins (Turkish if the highest-priority language starts with tr, otherwise English). 3) the language setting of your API key: Dashboard → API Keys → the settings button next to the key → “API error language”. 4) English when none of the above applies. Every key that already exists starts with tr (so nothing changes for current integrations); keys created from now on start with en. Exception: errors raised before authentication are always in English, because the key has not been resolved yet — 401 invalid_auth, empty_api_key, invalid_api_key_format, invalid_api_key and 429 too_many_attempts. For those responses you can still send Accept-Language: tr to get Turkish.

Common Errors and Solutions

invalid_api_key

Your API key is invalid or has been deactivated. Create a new key from the Dashboard. If the Authorization header is missing you get invalid_auth; if the key does not start with sk-ony- you get invalid_api_key_format.

insufficient_balance

Your balance is insufficient for this request. The required and available fields of the body show the required and the available amount. Top up or lower max_tokens (see Balance pre-check).

not_found

The requested endpoint or record was not found: a wrong path, a model that is not in the catalog in GET /v1/models/{model_id}, or a usage/transaction record that does not exist. In a chat request an unknown model returns 400 unsupported_model instead.

rate_limit_exceeded

You have exceeded the per-minute request limit. Wait a moment and try again.

daily_token_limit_exceeded

You have reached the daily token limit defined for this model. Ask your administrator (partner) for a new limit or wait for the daily reset.

monthly_token_limit_exceeded

You have reached the monthly token limit defined for this model. It resets on the first day of the month.

daily_request_limit_exceeded

You have reached the daily request-count limit defined for this model.

model_blocked

This model is blocked for the project/customer. Contact your partner or admin for access.

free_model_rate_limit

You have exceeded the free model usage limit. At most 5 requests can be sent within 24 hours.

payload_too_large

The request size is too large. If you are uploading a base64 image, shrink the image (max 10 MB) or send it directly via a public URL.

generation_failed

Video/image/music generation failed. This is usually a temporary issue with the upstream generation service — try another model or try again in a few minutes.

unsupported_model

The model id is not in the catalog or the model is currently inactive. For the current model list, call GET /v1/models.

model_not_allowed

403: your key has a model lock and the requested model is not in the allowed list (also returned when the model chosen by OnyRouter is not in the lock). On the Anthropic endpoints this is returned as 404 not_found_error.

free_model_not_eligible

403: on personal keys, free models (:tr, :free) are only available to verified accounts: sign in with Google or GitHub, a verified e-mail or a real balance top-up is required. Project and partner keys are not subject to this requirement. It does not count toward the quota; X-Should-Retry: false is returned.

daily_rate_limit_exceeded

429: the key's daily request limit (10,000 by default) has been reached. Retry-After gives the time until the end of the day; if that is longer than 60 seconds, X-Should-Retry: false is returned too and the SDKs do not retry.

tr_yogun / tr_concurrency_limit

429: the limit of :tr requests that can be processed at the same time has been reached (4 by default; per account for personal keys, per key for project and partner keys). Extra requests wait in a queue for a short time; if no slot frees up, this error is returned with Retry-After. It is not deducted from your daily quota.

tr_model_daily_limit

429: the daily request quota of :tr models is used up (shared across all :tr models). Retry-After gives the time until the quota renews.

unsupported_parameter / unsupported_tool

400: an unsupported field or tool type was sent to /v1/responses (e.g. previous_response_id, a file_id); code is unsupported_parameter or unsupported_tool and the param field names the field. On /v1/messages the same case is returned in the Anthropic format as 400 invalid_request_error; the field or tool name (e.g. file_id, code_execution) is stated in the error message.

upstream_timeout

504: the model response did not complete within the time limit. Use stream: true for long generations; if a stream is cut off, the part already generated is charged.

Want help finding the right model?