POST /v1/runs that never charges you twice. Read it before you put an integration in front of real traffic. For the list of every code, see Errors.
The error envelope
Every JSON error has one shape:- No
retryablefield. The status and the code tell you whether to retry. - No
Retry-Afterheader. You choose the backoff. - No
WWW-Authenticateheader on a401.
Match on code, never on message
provider_* code shares the message “the provider call failed”, and the deadline_exceeded message says “before a route was chosen” even when the model call is what timed out. When you meet a code your client does not know, fall back to its status family below.
Errors that are not JSON
A few rejections come from the web layer before OpenType’s own handlers run. Their bodies are plain text or empty, and they have norequest_id in the body. The x-request-id response header is still set.
The runs routes (
/v1/runs...) wrap the same failures into JSON: 400 invalid_body and 413 body_too_large. Everywhere else, parse defensively: try JSON, and if that fails, keep the status, the raw text and the x-request-id header.
What to do, by status
A
429 is always a quota refusal, never a rate limit, so retrying it quickly does not help. Nothing was stored, so a later retry may reuse the same key. The helper below leaves 429, like every other 4xx, to your code.
Why a 5xx needs a new idempotency key
POST /v1/runs stores the run before it calls the model. When a 5xx comes after that point, the stored run does not run again under the same key:
- If the run failed after a model call, it is settled as
failed. The same key replays it as200with"state": "failed". - If the run failed before a model call (
no_route_available,decision_unavailable,deadline_exceeded, mostprovider_*codes), it stayspending. The same key replays it as202indefinitely.
5xx must use a new key. A retry after no response must use the same key, because you do not know whether the first attempt was stored. Idempotency has the full table.
A retry helper for POST /v1/runs
The helper:- sends the body with a key derived from your business id,
- retries
500,503and504with exponential backoff and jitter, and a new key on each attempt (<base>:r1,<base>:r2, …), - retries a timeout or a dropped connection with the same key,
- never retries a
4xx, - returns the run, including a
200with"state": "failed"or a202with"state": "pending", for you to handle.
Retrying other routes
OnlyPOST /v1/runs takes an idempotency key. For the rest:
What goes wrong
Related
- Errors - every code, grouped by status, with its message.
- Problem codes - one page per code, with causes and fixes.
- Idempotency - when a key replays, conflicts, or must be replaced.
- Request ids - send your own
x-request-idand find a request later. - API reference - request and response schemas for every route.