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:(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
Idempotency vs webhook event_id
Two separate ideas that solve opposite-direction problems:
You use both — client-side keys for safe POST retries, event_id
dedup for safe webhook replays.
Works on which endpoints
AllPOST / 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).
