Error reference
Every error, on every /v1 path, is JSON in one envelope — including 404 for unknown paths and 405 for wrong methods, so response.json() never breaks on an Oogam error. Program against error.code — codes are stable; the human-readable message may improve over time.
{
"error": {
"message": "'input' exceeds the 5,000 character limit per request.",
"type": "invalid_request_error",
"code": "input_too_long"
}
}Codes by status
| Status | Code | What happened | Retryable? |
|---|---|---|---|
| 400 | invalid_json | Body was not valid JSON. | No — fix the request. |
| 400 | missing_input / input_too_long | Required input absent or over its limit (TTS 5,000 chars; embeddings 16,000/input). | No — chunk the input. |
| 400 | missing_language / invalid_language | Language missing or unknown — the models never auto-detect. | No — send a valid code (list). |
| 400 | invalid_voice | Voice id not in the catalogue. | No — pick from GET /voices. |
| 400 | missing_file | Multipart form had no file part. | No. |
| 400 | tools_not_supported | tools/tool_choice sent to /chat/completions. | No — remove them; use response_format. |
| 400 | invalid_response_format / model_not_text | Unsupported response_format.type, or a non-text model on the text endpoint. | No. |
| 400 | invalid_temperature / invalid_max_tokens | Sampling parameter out of range (temperature 0–2, max_tokens ≥1). | No. |
| 400 | missing_messages / too_many_messages / invalid_message | Chat messages empty, over 200, or non-string content. | No. |
| 400 | invalid_url / invalid_request | KB URL not http(s), or KB name not 1–120 chars. | No. |
| 400 | batch_too_large | Embeddings batch over 96 inputs. | No — split the batch. |
| 400 | kb_limit_reached / kb_document_limit_reached / unsupported_file_type / file_too_large | Knowledge-base limits — see Knowledge Bases. | No. |
| 400 | missing_input | KB document upload had no file, url, or text. | No. |
| 401 | missing_api_key | No Authorization: Bearer header. | No — add the header. |
| 401 | invalid_api_key / revoked_api_key / expired_api_key | The key is wrong, revoked, or past its expiry. | No — use a current key. |
| 402 | insufficient_credits | The project wallet is empty. | After top-up. |
| 402 | spend_limit_exceeded | The project's monthly cap is reached. | After raising the cap. |
| 403 | insufficient_permissions | The key lacks this product (type permission_error). | No — enable the product on the key. |
| 403 | api_not_available | This product's API is not public yet. | No — contact us for early access. |
| 403 | project_archived / account_suspended / org_required | The project/account is inactive, or the key has no workspace (KB). | No. |
| 404 | model_not_found | Unknown model id — see GET /models. | No. |
| 404 | not_found | Unknown path, job id, kb_id or doc_id. | No. |
| 405 | method_not_allowed | Wrong HTTP method — the Allow header lists valid ones. | No. |
| 413 | payload_too_large / prompt_too_large | Upload or body over the cap (STT 200 MB, isolate 150 MB, others 25 MB; JSON bodies 256 KB–4 MB; chat messages 100k chars). | No — compress or split. |
| 429 | rate_limit_exceeded | Too many requests this minute for this key. | Yes — wait Retry-After seconds. |
| 429 | too_many_sessions | Concurrent realtime session cap reached (see limits below). | Yes — after a session ends. |
| WS event | context_too_large | Realtime set_context.system over 8,000 characters. Carries active_context: "previous" (old prompt still live) or "none". | No — shorten the prompt and resend. |
| WS event | no_active_context | The session's only set_context was rejected, so there is no system prompt; start_utterance, say and audio are refused rather than running an uninstructed agent. | No — send a valid set_context, then start the call. |
| WS event | say_too_long | Realtime say.text over 500 characters per chunk. | No — split into sentences. |
| WS event | invalid_voice (realtime) | Voice id is not f1–f4/m1–m4 or a v_… clone id. | No — pick from GET /voices. |
| WS event | kb_not_found | The kb_id in set_context does not exist for your account. | No — check the id, or create the KB. |
| WS event | kb_empty | The knowledge base has no documents in ready status. | After a document finishes ingesting. |
| WS event | kb_not_available | The session has no workspace (e.g. a demo token), so a KB cannot be attached. | No — connect with an API key. |
| WS event | kb_no_room | The system prompt leaves no budget for knowledge-base content. | No — shorten the prompt. |
| WS event | language_at_capacity | Per-language concurrent-call capacity reached. | Yes — back off, retry shortly. |
| 502 | upstream_error | The model failed or was unreachable. | Yes — backoff below; report if persistent. |
| 502 | json_generation_failed | The model could not produce valid JSON after a retry. | Yes — simplify the instruction or retry. |
| 503 | model_not_configured | This model has no active provider on the deployment. | Yes — after Retry-After; contact support if persistent. |
Rate limits & session caps
| Limit | Default | On exceed |
|---|---|---|
| Requests per key | 60/minute (adjustable per key in the dashboard) | 429 rate_limit_exceeded + Retry-After |
| Concurrent realtime sessions per API key | 5 | 429 too_many_sessions on upgrade |
| Concurrent Live talk calls per user | 2 | 429 too_many_sessions on upgrade |
| Max realtime session length | 120 minutes | Close 1000 "Session length limit reached" |
Higher limits are available per plan — contact us.
# 429 and 503 responses include how long to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 60Async STT job failures
Polling GET /audio/transcriptions-status/{id} can resolve to 200 {"status":"failed","error":"…"}. Failed jobs are never billed. If the same file fails repeatedly, re-encode it as WAV and retry — and tell us; deterministic failures on valid files are model bugs we chase.
Realtime WebSocket closes
| Close code | Meaning | Retryable? |
|---|---|---|
1000 / 1001 | Normal close / server restarting. | Yes — reconnect. |
1011 | Transient engine trouble ("Realtime service unavailable / slow — try again"). | Yes — reconnect with backoff (below). These recover within a minute in practice. |
4402 | Wallet ran out mid-call. | After top-up. |
| HTTP 401 on upgrade | Bad or missing credentials — see realtime auth. | No. |
| HTTP 429 on upgrade | too_many_sessions or connect throttle; Retry-After is included. | Yes — after the header's delay. |
Session state does not survive a reconnect. The engine keeps no conversation memory across connections — after any close, reconnect and replay your setup (set_lang → set_voice → set_context → optionally a resume line via say). For a caller on the line, keep the telephony leg open, play a brief hold prompt, and reconnect the engine leg behind it.
// Recommended retry loop for retryable codes (1011, 502, 429, 503):
for (const delayMs of [1000, 2000, 4000]) {
const ok = await tryOnce();
if (ok) break;
await sleep(delayMs);
}