Errors and Rate Limits

Errors use OpenAI’s envelope on both endpoints, so error handling written against the OpenAI SDK works unchanged:

1{
2 "error": {
3 "message": "The rate limit for your plan has been exceeded.",
4 "type": "rate_limit_error",
5 "code": "rate_limit_exceeded",
6 "status": 429
7 }
8}

type is one of invalid_request_error, authentication_error, permission_error, rate_limit_error or server_error. code is the stable machine-readable value to branch on; message is for humans and may change.

A 402 for a blocked account uses its own shape, carrying message, code and data.reason at the top level rather than inside error. Branch on the status code before reading error, so a blocked account surfaces as the billing problem it is rather than as a parsing failure.

What to do with each status

StatusMeaningRetry?
400The request is malformed, or a parameter is invalid for this endpointNo. Correct the request.
401The API key is missing or not validNo.
402The account cannot currently be billedNo.
403The key is valid but not permitted to do thisNo.
404No such response id, or it is no longer storedNo.
429Your plan’s rate limit is exhaustedYes, with backoff.
500Something failed on our sideYes, with backoff.
502A transient upstream failureYes, with backoff.

Retry 429, 500 and 502 with exponential backoff and jitter, and give up after a small number of attempts rather than retrying indefinitely. A 4xx other than 429 will return the same result however many times you send it.

Creating a response is not idempotent. If a POST /v1/responses times out on your side, the run may still have started, so retrying can produce a second run. Prefer "background": true for long work: it returns an id immediately, and you poll for the outcome instead of holding a request open.

Errors worth knowing about

These come from specific combinations rather than from a malformed body, so they are easy to hit while everything looks correct:

ConditionStatus
A top-level field the endpoint does not recognize, including a misspelling like max_token400, code: "unknown_parameter", with the field named in param
"background": true with "store": false400
?stream=true retrieving a response that was not created with "background": true400
A reasoning.effort outside none, minimal, low, medium, high400
A tool whose type is not function, on /v1/responses400
Chaining previous_response_id onto a run that has not finished409
Retrieving or chaining a response older than the storage window404

Failures inside a stream

A stream can fail after it has started, so a 200 on the initial request is not the whole story.

On /v1/chat/completions, read finish_reason on every chunk rather than assuming the stream ended cleanly, and treat a connection that drops before data: [DONE] as an incomplete reply. See Chat Completions API.

On /v1/responses, a failed run ends with a response.failed event and a run that stopped early ends with response.incomplete. Both are terminal, so receiving either means no more events are coming. See Responses API.

Planner mode has its own partial failures: an agent can be slow, refuse, or not reply. The planner treats those as normal and works around them, so a run that lost an agent still returns an answer.

Rate limits

A 429 means your plan’s limit is exhausted rather than that anything is wrong with the request. Back off and retry.

Limits are scoped to your plan and are visible in your ASI:One account.

Next steps

  1. Chat Completions API - The default endpoint, including streaming
  2. Responses API - Retrieve, chain and cancel by id
  3. OpenAI Compatibility - Which parameters are supported on each endpoint
  4. API Reference - Every status code each endpoint returns