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

# Idempotency

> Retrying safely when the network lies to you.

A network timeout tells you nothing about whether the request arrived. Without a
way to say "this is the same request", your only options are retrying and
risking a double charge, or not retrying and losing the work.

Send an `Idempotency-Key` — any unique string up to 255 characters, a UUID by
convention:

```bash theme={null}
curl https://api.voice.wixzel.com/v1/calls \
  -H "Authorization: Bearer $WIXZEL_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"to": "+14155551234", "agent_id": "ag_01HXYZ"}'
```

## Where it is required

`POST /v1/calls` and `POST /v1/billing/topups` — the two paths that spend money.
Omitting it returns `400 missing_idempotency_key`. Other mutating endpoints
honour the header if you send it.

## What happens on a retry

Replaying the same key with the same body returns the **original** response —
same status, same body — with an extra header:

```
Idempotent-Replay: true
```

Keys are retained for **24 hours**. After that the same key is a new request.

## Two ways it can refuse

| Status | Code                        | Meaning                                                                                                                   |
| ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `422`  | `idempotency_key_reuse`     | Same key, **different body**. You reused a key for a genuinely different request — almost always a bug in key generation. |
| `409`  | `idempotency_key_in_flight` | The first request is still running. Wait and retry; do not race it.                                                       |

<Note>
  Generate a **new** key per logical operation, not per attempt. Retrying a failed
  call with a fresh key is a second call. Retrying it with the same key is the
  same call.
</Note>
