Skip to main content

Idempotency

Network hiccups make clients retry. A retried send without protection is a duplicate push. POST /v1/notifications and POST /v1/campaigns accept an Idempotency-Key header to make retries safe.

curl -X POST https://push.example.com/v1/notifications \
-H "Authorization: Bearer sk_live_…" \
-H "Idempotency-Key: order-48213-shipped" \
-H "content-type: application/json" \
-d '{ … }'

Rules

SituationResponse
First requestProcessed normally; status + body stored for 24 hours.
Same key, same body, within 24 hThe stored status and body, plus header Idempotent-Replayed: true. Nothing is sent again.
Same key, different body422 idempotency_key_reused
Same key while the first request is still being processed409 idempotency_in_progress — retry shortly
Request failed validation (422)The key is not consumed; fix the body and retry with the same key.
Request failed after validation (5xx)The claim is released; retry with the same key.

Keys are scoped per app and per endpoint — the same string on /v1/notifications and /v1/campaigns are two different keys. Use something that identifies the intent: an order id plus the event name, a job run id, a UUID you generated before the first attempt.

Storage: the idempotency collection with a TTL index; the stored body is bound to a SHA-256 of the request body.

Endpoints without it

/send, /cancel and /experiment/winner are naturally idempotent through status transitions: sending a campaign that is already sending answers 409 invalid_state, cancelling twice is harmless, a second winner answers 409.