API REFERENCE
Errors
The error shapes, every status and code the documented endpoints return, and how to handle each.
Application errors use one envelope with a stable code you can branch on and a message written for a person:
ENVELOPE
{ "error": { "code": "model_not_found", "message": "Model 'gpt-4o' is not in the model registry" } }Request validation (422) and a few input checks (400) use the framework's shape, { "detail": ... }. Always read the HTTP status first, then error.code if present.
Status and codes
| Status | error.code | Meaning | Retry? |
|---|---|---|---|
| 400 | model_not_found | Unknown model id, or a family your account cannot call. | No. Fix the id or request access. |
| 400 | — | Input check, e.g. more than 64 embeddings inputs. Body { "detail": "..." }. | No. |
| 401 | authentication_required | No Authorization header. | No. Send the key. |
| 401 | invalid_api_key | Unknown, malformed or revoked key. | No. Create a new key. |
| 402 | insufficient_credits | The wallet cannot cover the request. required_usd, available_usd, allowed_actions. Nothing was charged. | After funding. |
| 403 | zero_entitlement_required | Not enrolled in ZERO Alpha. | No. |
| 404 | capability_unavailable | The capability is not enabled (image generation). | No. |
| 413 | request_too_large | max_tokens is above the model's limit. | No. Lower it. |
| 422 | — | Invalid body. { "detail": [ ... ] } lists each problem with its location. | No. Fix the body. |
| 502 | — | Embeddings are temporarily unavailable. | Yes, with backoff. |
| 503 | zero_capacity_unavailable | A ZERO limit closed. error.limit names it and error.reset_at says when it clears. | After Retry-After. |
| 503 | zero_program_disabled | ZERO is switched off by Tessen. | Not until Tessen re-enables it. |
503 ZERO_CAPACITY_UNAVAILABLE
{ "error": { "code": "zero_capacity_unavailable", "message": "You have used today's free ZERO Alpha request allowance.", "capacity_state": "exhausted", "limit": "requests", "owner": "you", "actions": ["wait", "add_credits", "learn_tessen_node"], "reset_at": "2026-10-30T00:00:00+00:00" }}Handle an error in code
BRANCH ON STATUS AND CODE
curl -i https://api.tessen.ai/v1/chat/completions \ -H "Authorization: Bearer $TESSEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "not-a-model", "messages": [{"role": "user", "content": "hi"}]}'import osimport requests response = requests.post( "https://api.tessen.ai/v1/chat/completions", headers={"Authorization": f"Bearer {os.environ['TESSEN_API_KEY']}"}, json={"model": "not-a-model", "messages": [{"role": "user", "content": "hi"}]}, timeout=60,)if response.ok: print(response.json()["choices"][0]["message"]["content"])else: detail = response.json() error = detail.get("error", {}) # 401, 402, 403, 400 and 503 use {"error": {...}}; 422 uses {"detail": [...]} print(response.status_code, error.get("code"), error.get("message")) if response.status_code == 503 and error.get("reset_at"): print("retry after", error["reset_at"], "| Retry-After:", response.headers.get("Retry-After"))const response = await fetch("https://api.tessen.ai/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${process.env.TESSEN_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ model: "not-a-model", messages: [{ role: "user", content: "hi" }] }),});if (response.ok) { console.log((await response.json()).choices[0].message.content);} else { const detail = await response.json(); const error = detail.error ?? {}; // 401, 402, 403, 400 and 503 use { error: {...} }; 422 uses { detail: [...] } console.log(response.status, error.code, error.message); if (response.status === 503 && error.reset_at) { console.log("retry after", error.reset_at, "| Retry-After:", response.headers.get("Retry-After")); }}Streaming
A refusal on a streamed request arrives as an error frame inside HTTP 200, with type where a non-streaming response has code. See Streaming.