Skip to main content
A request that times out leaves you guessing: did it land? Retrying might send a second message or create a second contact. Send an Idempotency-Key and the guess goes away.
Retry that exact request and you get the original response back, with Idempotency-Replayed: true. One contact exists, not two.

Where it works

Every write endpoint — every POST, PATCH and DELETE under /v1. The header is optional; omit it and the endpoint behaves exactly as it always did. Reads ignore it.

How to choose a key

Derive it from the thing you are acting on, not from the attempt:
A key generated per attempt protects you from nothing, because the retry carries a different one. Keys are scoped to your workspace and mode, so they cannot collide with another customer’s. Maximum 255 characters.

What each outcome means

The key is reserved before any work happens, then the response is recorded against it.
You get the original status code and body, plus Idempotency-Replayed: true. No second message, no second charge.
A reused key with changed content is a bug on the caller’s side, so LazyApp refuses rather than guessing which one you meant.
The first attempt has not responded yet. Wait and retry; do not treat it as a failure.

Server errors release the key

A 5xx is not recorded. The key is freed so your retry actually runs — which is what you want, because the original attempt may never have completed. Responses that are not JSON, such as a media download, are also not recorded.

How long a key lasts

24 hours from first use. After that the key is forgotten and reusing it starts a fresh request.

Message-level deduplication

POST /v1/messages and POST /v1/events also accept an idempotency_key in the body. That is an older, narrower guarantee: it deduplicates the message or event itself in the database, and it is enforced permanently rather than for 24 hours. The two coexist. Use the header for transport safety; use the body field when you need a permanent guarantee that one business event produces one message, forever.

Retry recipe

For a robust integration:
  1. Generate one key per logical write (for example order-1042-shipped).
  2. Send Idempotency-Key: <key> on the request.
  3. On network error, timeout, or 5xx: retry with the same key and body.
  4. On Idempotency-Replayed: true: treat as success — it was a replay.
  5. On 409 (in progress): wait briefly and retry with the same key.
  6. On 429: back off; see rate limits.
Do not generate a fresh UUID per attempt. That is the classic bug that makes retries create duplicates.
Workflow-tool pitfall. If n8n, Zapier, or a queue reuses one execution-level request id across several HTTP nodes, every call after the first looks like a replay of the first. Use a distinct key per node (or omit the header and rely on the body idempotency_key for sends).
X-Request-Id is a correlation id for support logs. It is not an idempotency key — do not reuse it to prevent double-sends.