> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqwish.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Reliable retries

> Recover resource creation and inference with stable operation identities.

Start with a creation operation that actually supports idempotency. Save this as `dataset.json`:

```json theme={null}
{
  "name": "Retry format example",
  "examples": [
    {"context":"Please refund the duplicate charge.","decisions":[{"id":"refund","kind":"binary","question":"Is a refund requested?"}],"targets":{"refund":{"yes":1,"no":0}}},
    {"context":"Where is my parcel?","decisions":[{"id":"refund","kind":"binary","question":"Is a refund requested?"}],"targets":{"refund":{"yes":0,"no":1}}}
  ]
}
```

Choose one key for this intended dataset creation. Persist it and the body before sending; keep both unchanged across retries and process restarts.

```bash theme={null}
export D1_OPERATION_KEY='retry-format-example-v1'

curl --fail-with-body --connect-timeout 5 --max-time 40 \
  https://console.sqwish.ai/v1/datasets \
  -H "Authorization: Bearer $D1_API_KEY" \
  -H "Idempotency-Key: $D1_OPERATION_KEY" \
  -H 'Content-Type: application/json' --data-binary @dataset.json
```

If the reply is lost, run the same request again. It returns the existing dataset rather than creating another one. Changed input with the same key produces an idempotency conflict. To intentionally create another dataset, use a new key.

## Retry within a budget

For supported creates, a later attempt can recover an uncertain outcome using the same key. For an explicit error response, inspect `error.retryable` and `code` before repeating it. Respect `Retry-After` when present; otherwise use bounded exponential backoff with jitter. Stop when the attempt or elapsed-time budget is exhausted and keep the operation record for later recovery.

Do not retry validation errors with unchanged input. Correcting the input is a new intended operation and should get a new key. The [API behavior guide](/api#supported-idempotency) lists operations that support the header. The source [SDKs](/guides/sdks) implement bounded retries for eligible calls.

## Inference after a lost response

For `POST /v1/decide`, `/v1/systemone` and the Claude Code hook, persist a unique `Idempotency-Key` alongside the exact request before the first attempt. If the reply is lost, resend both unchanged. A replay uses the original accepted model versions and tariffs, even if a named model was promoted in the meantime. Its settlement is not repeated.

Responses are retained for 24 hours. After that, the operation identity remains and the old key returns `idempotency_response_expired`; it never starts another inference. A still-running operation returns `request_in_progress`. A terminal failure remains the same failed operation. Reuse a key only for recovery; use a new one when you intentionally request another execution.

Each replay attempt consumes the account's read quota, including pending, conflicting, failed and expired attempts. Respect `Retry-After` and use bounded backoff. Keep downstream actions such as assigning a ticket tied to your application's operation ID so retries cannot duplicate them.

`store: true` independently controls learning and feedback storage. It is not required for replay. Usage history helps diagnose an operation but does not contain the saved answer; retrying the original request with its key retrieves that answer while it is retained. Preserve request IDs and charge metadata.

## Mutations need their own recovery rule

After a lost promotion response, read the model's production version. After a lost rollback response, read it before doing anything else: rollback swaps production and previous, so repeating it can undo the recovery. After a lost API-key creation response, the secret cannot be read from the key list; inspect and revoke unwanted keys before deliberately creating another.

A timeout while polling a job stops the client waiting. The job can still be running. Read it again or explicitly cancel it according to your intent.
