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.
curl command again. Keep the key and the body exactly as they were.
When to retry
Retry whenerror.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).
- If the response has a
Retry-Afterheader, wait that long. - Otherwise wait
0.25 * 2^attemptseconds. Add a little random jitter, so that many clients don’t retry at the same moment. - Cap the wait.
- 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.
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:
Idempotency keys
Make oneIdempotency-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
ForPOST /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 asdataset.json:
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.
servedoradapterrefuse the call if the model moved since you looked (Switch a family or a model on).
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.