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

# Idempotency

> Safe retries for POST requests using Idempotency-Key.

<Warning>
  **v1.1 feature.** The `Idempotency-Key` header is accepted but not
  yet enforced end-to-end. Setting it today is harmless and forward-
  compatible. Until v1.1 lands, design your client code assuming our
  side may not dedupe on retries — use the webhook
  [event\_id idempotency](/webhooks/overview) pattern instead.
</Warning>

## The problem

Your POST to `/api/v1/leads:bulk` timed out. Did we receive it?
Retrying naively could double-insert. Retrying with an idempotency
key lets us recognize the retry and return the original response.

## How it'll work

Send a unique header on write endpoints:

```http theme={null}
POST /api/v1/campaigns/abc/leads HTTP/1.1
Authorization: Bearer yt_live_...
Content-Type: application/json
Idempotency-Key: 8a4c1f3e-9c21-4b7d-8e8a-9b1e2f3a4c5d

{"phone": "9876543210"}
```

We'll dedupe on `(tenant_id, key)` for 24 hours. Retries with the
same key within that window return the original response (same
HTTP status, same body).

## Generating keys

Use a UUID v4 per logical operation. The **operation**, not the
attempt: if attempt 2 has a different key than attempt 1, we
treat them as independent requests.

```python Python theme={null}
import uuid
key = str(uuid.uuid4())

for attempt in range(3):
    try:
        resp = client.post("/api/v1/leads", headers={"Idempotency-Key": key}, ...)
        break
    except ClientError:
        continue  # same key — safe to retry
```

## Idempotency vs webhook event\_id

Two separate ideas that solve opposite-direction problems:

| Concept           | Direction                    | Dedup key                         |
| ----------------- | ---------------------------- | --------------------------------- |
| `Idempotency-Key` | Your client → our API        | You pick a UUID per logical write |
| `event_id`        | Our webhooks → your endpoint | We pick a UUID per logical event  |

You use both — client-side keys for safe POST retries, event\_id
dedup for safe webhook replays.

## Works on which endpoints

All `POST` / `PUT` / `PATCH` on `/api/v1/*` once shipped. `GET` /
`HEAD` / `DELETE` don't need it (already idempotent by HTTP semantics,
modulo DELETE being "at most once" — we return 204 whether or not
the resource previously existed).
