Skip to content
Zabio is in beta: models, prices and features can change. Tell us what breaks at hello@zabio.ai.

Errors

Every error uses OpenAI’s envelope, so SDKs raise their usual exception types:

For the exact shape of every request and response, with curl, Python and Node examples, see the API reference.

{
"error": {
"message": "'temperature' must be between 0 and 2.",
"type": "invalid_request_error",
"param": "temperature",
"code": "invalid_value"
}
}

type is one of invalid_request_error, permission_error, billing_error, rate_limit_error or server_error. param names the offending field when there is one. The x-request-id header is set on every response; quote it when you write to support.

code Meaning
invalid_json the body is not valid JSON or could not be read
no_model_allowed an auto request whose model access leaves auto no model it can use. The message says which level to check: account, organization, project or key. See Model access
missing_messages messages absent or empty (a missing model means auto)
too_many_messages, too_many_tools more than 4096 messages or 256 tools
invalid_value a field is out of range or malformed; param says which
unsupported_parameter a field Zabio does not implement (n above 1, logprobs, audio, prediction, web_search_options, non text modalities, the legacy function role); tools sent to a model that cannot take them through Zabio (today gpt-6-astra)
invalid_image_url an image could not be fetched or is not allowed; see Chat completions
byok_key_invalid your organization’s own vendor key was rejected by the vendor; update it under Billing, vendor keys. Zabio never falls back to its own key
upstream_invalid_request the vendor rejected the request; the message carries the vendor’s reason
unsupported_for_model the model you named cannot do what the request asks; param names the field (jev-1.13.0 answers typed questions from a json_schema only, never text, tools, images or a stream)
conversation_mismatch, conversation_too_large, context_length_exceeded Responses API; see Responses API

code: invalid_api_key when the key is missing, incorrect or revoked; the message says which. Keys are sent as Authorization: Bearer zb_live_....

code: key_expired when the key’s expiration has passed: "This API key expired on 2026-11-01 00:00 UTC. Create a new key or change its expiration in the web app." A key’s expiration is set when it is created or later in its Edit panel; its creator gets an email 7 days before. Background responses and batches the key queued before it expired end with the same code.

{"error": {"message": "Your organization has no credits left. Add credits at zabio.ai/billing to continue.", "type": "billing_error", "code": "insufficient_credits"}}

Returned before any vendor work, only when a zero balance means no service: the organization is set to stop at zero, or it is a person’s second organization, which has no Free allowance. Every other organization at zero runs on the Free limits instead (see Billing, “The Free plan”) and gets the free_tier_* codes below. The header x-zabio-balance-micros carries the balance. A named model served on your own vendor key is not refused; auto is, whatever keys you hold, because the classifier runs on Zabio’s key. A batch or a background response whose estimated cost exceeds the available balance is refused with this code too.

code Meaning
insufficient_scope the key lacks the scope for this endpoint (chat, embeddings or conversations)
organization_suspended the organization is suspended
conversations_closed stored conversations are closed for this organization
free_tier_model the request names a model that is not on the free model list while the organization runs on the Free limits. The message is “Top up your account to unlock this model” with the top-up link; auto keeps working and picks among the free models. GET /v1/models marks locked models with zabio.availability: locked
free_tier_limit with param members or api_keys the Free plan’s account caps, on the dashboard API: one member and two API keys until the first top-up

model_not_found: the model does not exist, or a level of the key’s model access (the account, the organization, the project or the key) does not allow it; an auto line a level unchecked is refused the same way. The Responses API adds previous_response_not_found, conversation_not_found and response_not_found.

payload_too_large: the body exceeds 32 MB.

Every 429 carries a Retry-After header with the number of seconds to wait. Four limits exist:

code Scope Details
rate_limit_exceeded API key the key’s requests per minute or tokens per minute bucket is empty. Defaults: 600 requests and 200,000 tokens per minute; set per key. The token bucket is charged up front with the input estimate plus the output budget, clamped to what the served model can produce, and settled after the call to the real usage; a max_tokens far above what the job needs can hit the limit early, so set it near what you need. Headers x-ratelimit-limit-*, x-ratelimit-remaining-* and x-ratelimit-reset-* for requests and tokens are set on every response
quota_exceeded key or member (organization level) the key’s spend limit is reached for its period (a day, a week from Monday or a month, from 00:00 UTC, or the key’s whole life), or the monthly quota of the member who created the key is reached. The message says when it resets, for example "This API key's spend limit of 5.00 USD has been reached. It resets on 2026-10-19 at 00:00 UTC.". Headers x-zabio-quota-scope (key or member), x-zabio-quota-limit and x-zabio-quota-remaining are set
ip_rate_limit_exceeded client address too many requests from one address, checked before authentication. Default 300 per minute. Headers x-ratelimit-*-ip are set only on the refusal
upstream_rate_limited vendor the vendor is rate limiting and every fallback was exhausted
free_tier_limit organization, on the Free limits one of the Free limits is met; param and the header x-zabio-free-limit name it: requests_per_day (100 successful requests a UTC day; Retry-After is the time to 00:00 UTC), requests_per_minute (20), daily_cost (the daily fair-use limit; it resets at 00:00 UTC), input_tokens (the request has more than 16,000 input tokens; no Retry-After, send a shorter request) or max_tokens (an explicit max_tokens above 2,000; lower it or leave it unset). The message says which limit, when it resets, and that a top-up removes every limit. The Free rate-limit headers (x-ratelimit-*-requests-day and the minute bucket in x-ratelimit-*-requests) are on every Free response, refusals included. See Billing

rate_limit_exceeded, quota_exceeded and free_tier_limit use type: rate_limit_error.

Status code Meaning
500 internal_error an unexpected condition; the cause is never in the body
502 upstream_error the vendor returned an error or an unreadable response after retries and fallbacks. Retry-After: 5 when a retry makes sense
503 no_provider_available no healthy provider for this request right now; Retry-After: 5
503 vendor_unavailable the call named a model on a provider that is not available through Zabio right now; call another model or auto, or retry later; Retry-After: 5
503 auth_unavailable, billing_unavailable, conversations_unavailable a Zabio dependency is temporarily unavailable
503 free_tier_unavailable the counters behind the Free limits could not be read, so a free call is refused rather than served unmetered; retry shortly. Paid calls are not affected. Also the answer of GET /v1/public/free-tier when the list cannot be read
504 upstream_timeout the vendor did not answer in time; Retry-After: 5

A call that Zabio has kept alive for more than 90 seconds (see “Long calls” in the chat completions and Responses guides) already has its 200 status on the wire when the vendor fails, so the error travels in the body instead:

Call Shape
chat completions, not streamed a chat.completion with choices: [] and an error object beside it (message, type, code)
chat completions, streamed data: {"error": {"message", "type", "code"}} then data: [DONE]
Responses, not streamed the response object with status: "failed" and error: {"code", "message"}
Responses, streamed a response.failed event carrying that object

The code values are the same as in the tables above. Check error whenever choices is empty or status is failed.

When a provider fails, Zabio retries on the next eligible model according to the routing rules (up to 3 attempts; explicit models follow zabio.fallback). Only when every option is exhausted do you see a vendor error. The vendor’s body never reaches you; x-zabio-vendor names the vendor that failed and the message carries the vendor’s reason for 400s. Content the vendor refuses to produce comes back as a normal response with finish_reason: "content_filter", not as an error.

During streaming, a failure after the stream has started is reported as an error object inside a chunk (chat completions) or an error event (Responses API), and the stream ends.

  • missing_field (400): a required field such as input, or an item role, content or call_id is missing. A missing model means auto.
  • previous_response_not_found and conversation_not_found (404) on POST /v1/responses; response_not_found (404) applies to GET and DELETE /v1/responses/{id}.

The full list per endpoint is in the API reference.