Errors
The Strata HTTP API returns errors as RFC 7807 problem documents. Every non-2xx response uses the same shape, so you can write one handler for the whole /v1/* surface.
Response shape
All errors return Content-Type: application/problem+json and a JSON body with these fields:
| Field | Type | Description |
|---|---|---|
type | string | A URI identifying the error class, e.g. https://api.strata.kronisys.com/errors/rate_limit_exceeded. The slug after /errors/ is the stable identifier — branch on it. |
title | string | Short human summary. Safe to log. |
status | integer | HTTP status code, mirrors the response status. |
Some errors add extra fields for context — for example a 403 model_not_allowed includes requested_model and allowed_models, and a 429 includes retry_after, used, and limit. Treat any field beyond type/title/status as optional and tolerate its absence.
TipBranch on the
typeURI — match the stable slug after/errors/, not the HTTP status code ortitle. Thetitlestring may change; the type URI will not.
Error catalog
The type field is always the full URI https://api.strata.kronisys.com/errors/<slug>. The catalog lists the <slug> for readability.
| Status | Slug | When you get it |
|---|---|---|
| 400 | invalid_request | Body failed validation — required field missing, wrong shape, or unparsable. |
| 400 | unsafe_image_ref | A document-generator spec referenced a local file path or a disallowed image source. Only inline data: URIs and public https:// URLs are accepted. |
| 401 | missing_token | No Authorization: Bearer header was sent. |
| 401 | invalid_token | Token is malformed, unknown, expired, or revoked. Strata deliberately does not distinguish these — issue or rotate a key from Admin → API Keys. |
| 402 | subscription_required | Your organization has no active Strata subscription. An admin can start one in Billing. |
| 403 | insufficient_scope | Authenticated, but the key was not granted the scope this endpoint requires. Includes required_scope and granted_scopes. |
| 403 | trial_no_api_access | Your organization is on a self-serve trial. The API is not available during a trial — add a payment plan. |
| 403 | key_actor_revoked | The user (or connection bot) the key acts as is no longer active, so the key was disabled with them. |
| 403 | model_not_allowed | The requested model is not in the key's allowed models, or your organization has disabled it in the Model Catalog. Includes requested_model and allowed_models. |
| 403 | org_suspended | The key's organization is suspended. Contact your admin. |
| 404 | not_found | Resource (or /v1 route) does not exist or is not visible to this key's organization. |
| 404 | conversation_not_found | The conversation_id you referenced does not exist for this organization. |
| 409 | request_in_progress | A request carrying the same Idempotency-Key is still being processed. Wait for it to finish, then retry to fetch the cached result. |
| 413 | payload_too_large | Request body or uploaded file exceeds the endpoint limit (the JSON body cap is 1 MB; file uploads have their own cap). |
| 413 | spec_too_large | A document-generator spec exceeded the generator's own size limit. Split the document or trim the spec. |
| 422 | spec_invalid | A document-generator (/v1/excel, /v1/pdf, /v1/pptx, /v1/docx) rejected the spec you sent. |
| 429 | rate_limit_exceeded | The key's hourly request cap was exceeded. Honor Retry-After. |
| 429 | ip_rate_limit_exceeded | A coarse per-IP guardrail was tripped (before the key was even resolved). Honor Retry-After. |
| 429 | usage_limit_exceeded | The actor's per-user rate limit, or the organization's shared usage pool, was hit (the same cap the web app, Teams, and agents share). Includes unit, used, and limit. Honor Retry-After. |
| 429 | budget_exhausted | The key's monthly token budget — or the organization's token pool — is fully consumed. Resets on the organization's billing-cycle reset day. |
| 500 | internal_error | Strata encountered an unexpected failure. Safe to retry. |
| 500 | engine_returned_empty | A document generator produced an empty file. Safe to retry; if it persists, simplify the spec. |
| 500 | extension_config_error | The key's extension tools could not be safely initialized for this request. Retry; if it persists, check the actor's extension connections. |
| 503 | budget_check_failed | Budget enforcement is briefly unavailable (a transient backend hiccup). Strata fails closed rather than spend uncapped. Retry with backoff. |
| 503 | entitlement_check_failed | Strata could not confirm your organization's API entitlement. It fails closed rather than assume access. Retry shortly. |
| 503 | policy_lookup_failed | The organization's model/mode policy could not be read for this request. Strata fails closed. Retry with backoff. |
NoteToken-budget exhaustion returns
429, not403. Thebudget_exhaustedbody reportsused(committed tokens since the cycle reset),in_flight(estimated tokens reserved by currently-running requests), andlimit. Both the per-key budget and the shared organization token pool are enforced on the same call.
Examples
401 invalid_token
{
"type": "https://api.strata.kronisys.com/errors/invalid_token",
"title": "The provided API key is invalid, expired, or revoked.",
"status": 401
}
403 model_not_allowed
{
"type": "https://api.strata.kronisys.com/errors/model_not_allowed",
"title": "Model \"claude-opus\" is not currently allowed by this organization's policy. Pick an allowed model or have an admin update the org's allowed models.",
"status": 403,
"requested_model": "claude-opus",
"allowed_models": ["gpt-5.4", "gpt-5.4-mini", "claude-sonnet"]
}
429 rate_limit_exceeded
{
"type": "https://api.strata.kronisys.com/errors/rate_limit_exceeded",
"title": "API key rate limit exceeded (1000/1000 per hour). Retry after 42s.",
"status": 429,
"retry_after": 42,
"used": 1000,
"limit": 1000
}
A 429 rate-limit response also includes the Retry-After (seconds) and X-RateLimit-Reset (Unix epoch) headers, so you know exactly when to try again. Every successful response also carries X-RateLimit-Limit and X-RateLimit-Remaining.
Model governance and errors
The set of models a key may call is the intersection of your organization's allowed models, the key's allowed_models, and any role or per-user limits. Because your organization curates which models it enables from the central Model Catalog, a model that worked yesterday can return 403 model_not_allowed today if an admin disabled it — even if the key's own allowed_models still lists it. The organization's policy is always authoritative and is re-checked on every request.
TipDon't hard-code model IDs in retry logic. On a
403 model_not_allowed, readallowed_modelsfrom the response body and fall back to one of those, or surface the error to whoever provisioned the key.
How to handle errors
Build one error handler that reads type and decides what to do.
Retry on 5xx and 503
500, 503 budget_check_failed, 503 entitlement_check_failed, and 503 policy_lookup_failed are transient. Retry with exponential backoff (for example: 1s, 2s, 4s, 8s, cap at 30s) and a small amount of jitter. Cap total retries at 3–5 attempts.
KeyOn the non-streaming
POST /v1/chat, send anIdempotency-Keyheader on retries. Strata caches the first result for 24 hours and replays it on a repeat with the same key, so a network-timeout retry never creates a duplicate conversation or double-bills. While the first request is still running, a retry returns409 request_in_progress— wait, then retry to fetch the cached result. Idempotency is not applied to streaming requests; streaming clients recover by reconnecting, not re-POSTing.
Back off on 429
When you receive a 429, wait for the duration in Retry-After (or until the timestamp in X-RateLimit-Reset) before sending another request with the same key. A budget_exhausted 429 will not clear until the organization's billing cycle resets, so back off long rather than retry tightly. Spreading bursts across multiple keys is fine; hammering a throttled key is not.
Don't retry most 4xx
400, 401, 402, 403, 404, 413, and 422 will never succeed on retry without changing the request. Surface them to your caller or your logs, fix the underlying cause (bad payload, missing scope, disallowed model, expired key, rejected spec), then send a new request. The exception is 409 request_in_progress, which clears once the in-flight request completes.
Log the request context
Log the type, title, and any extra fields (such as allowed_models or required_scope) on every failure. Include them in any support request — they let the Kronisys Inc. team trace the exact problem without asking you to reproduce it.