Skip to main content
A call can fail, or its answer can be lost on the way back. Send each call with an Idempotency-Key, and you can send it again safely. A decision that already ran returns its first answer, and isn’t charged again. Zero data retention is the exception.
If the answer doesn’t arrive, run the same curl command again. Keep the key and the body exactly as they were.

When to retry

Retry when error.retryable is true. Also retry when the reply never arrived and you still have the Idempotency-Key. Check error.code as well before you repeat a call (Error codes).
  1. If the response has a Retry-After header, wait that long.
  2. Otherwise wait 0.25 * 2^attempt seconds. Add a little random jitter, so that many clients don’t retry at the same moment.
  3. Cap the wait.
  4. Give the call a budget of attempts or elapsed time. When the budget runs out, stop. Keep the operation’s record, so that you can recover it later.
Don’t retry a 402, a 422 or any other error with retryable: false until you have changed the account or the request. A corrected request is a new operation, so give it a new key. This sample follows the same policy for a plain httpx call, with a cap of 8 seconds:
If an operation ended in failure, its key returns that failure again. The operation doesn’t run a second time.

Idempotency keys

Make one Idempotency-Key for each operation you intend, and save it with the request. Retry that operation with the same key and unchanged input. For a raw upload, keep its exact bytes and name. The API reference shows the header only on the operations that support it. For inference:
  • A successful answer to a request sent with a key is saved, with its charge, before it is returned. It is kept for 24 hours.
  • A request sent without a key keeps no answer.
  • An organisation with zero data retention keeps no answer either (Zero data retention).
  • An operation that is still running returns request_in_progress, with retry guidance.
  • A replay of a failed operation returns that failure. It is not a new attempt.
  • After 24 hours the saved answer expires, but the operation remains. Its key then returns idempotency_response_expired, and never runs the decision again.

After a lost response

Send the same request again, with the same key and the same body.

Decisions

For POST /v1/decide, /v1/systemone and the Claude Code hook, save a unique Idempotency-Key with the exact request before the first attempt. If the reply is lost, resend both unchanged. A replay uses the models and prices the first request was accepted with. This holds even if its family moved to a newer model in the meantime. A replay isn’t charged again. Idempotency keys says what a replay returns while the call runs, after it fails and after 24 hours. Reuse a key only to recover a call. Use a new key when you want the decision to run again. Each replay attempt uses the account’s read budget (Rate limits). That includes pending, conflicting, failed and expired attempts. Respect Retry-After, and back off within a budget. Tie downstream actions, such as assigning a ticket, to your application’s own operation ID. Then a retry can’t repeat them. Your request history helps you diagnose an operation, but it doesn’t hold the saved answer. While the answer is kept, the original request with its key returns it. Keep the request IDs and the charge details.

Datasets and jobs

A create that supports idempotency recovers the same way. A later attempt with the same key settles an uncertain outcome. This example creates a dataset. Save it as dataset.json:
Choose one key for this dataset. Save the key and the body before you send them. Keep both unchanged across retries and process restarts.
If the reply is lost, run the same request again. It returns the existing dataset instead of creating another one. Changed input with the same key gets an idempotency conflict. To create another dataset on purpose, use a new key.

Zero data retention

An organisation with zero data retention keeps no answer. So a key isn’t honoured there. A retry runs the request again, and is charged again. That includes a retry an SDK makes by itself after a network error.

Switches, keep warm and API keys

Switches and keep warm have no general idempotency-key contract. After a lost response, read the family or model before you repeat the call.
  • A switch that is already where you asked changes nothing.
  • served or adapter refuse the call if the model moved since you looked (Switch a family or a model on).
After a lost response to making an API key, you can’t read the secret from the key list. Check the keys, and revoke any you don’t want, before you make another on purpose (API keys).

Polling timeouts

A timeout while you poll a job only stops your client waiting. The job can still be running. Read it again, or cancel it explicitly if that is what you want.

With the SDKs

The Python and TypeScript clients, sqwishai on PyPI and npm, follow this policy for eligible calls. They wait as Retry-After says, or back off for about 4 seconds at most, and stop after two retries. Retries explains their idempotency keys and options.