Skip to main content
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 pattern instead.

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:
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
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:
ConceptDirectionDedup key
Idempotency-KeyYour client → our APIYou pick a UUID per logical write
event_idOur webhooks → your endpointWe 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).