Skip to main content
A send is not free to repeat. If your request times out, or your job runner retries a failed step, or a proxy gives up waiting and your client tries again, the message goes out twice — and your customer sees it twice. That is true of every HTTP API that sends something, and it is why this one accepts an Idempotency-Key.
This header is optional. If you do not send it, nothing changes: the API behaves exactly as it always has, and a retry sends again. Everything below is opt-in.

The header

Pick a string that is unique to the message you are trying to send — an order id, a row id, a UUID — and send it with the request:
Sending with a key
Send that exact request again — same key, same body — any time in the next 24 hours, and you get the original response back, unchanged, and nothing is sent.

What each outcome looks like

Read Idempotency-Replayed to know which happened. false means this call did the sending; true means it was a replay. If the header is absent from the response, idempotency is not enabled on the deployment you are talking to and retries will send again — treat that as “not protected”.

Choosing a key

  • Make it unique per message, not per customer and not per day. order-4471-confirmation is good; daily-reminder is not, because tomorrow’s reminder is a different message that would be refused as a reuse.
  • 8 to 255 characters, from letters, digits, and . _ : ~ -.
  • A UUID is always a safe choice if you have nothing natural to use.
  • Reuse the same key for every retry of the same send. Generating a fresh key on retry defeats the entire purpose.

Two things it deliberately does not do

It does not merge different messages. Reusing a key with a changed body returns 422 idempotency_key_reused rather than quietly sending the new one or quietly replaying the old one. Both of those would be a lie about what your customer received. It cannot rescue a lost reply. If we genuinely delivered the message and only the response was lost on the way back to you, a retry sends again — the key was released when the request failed, because the far more common case is a request that never got through at all. No key can tell those two apart from our side. If exactly-once matters more to you than delivery, wait and check rather than retry.

When to bother

Worth it

Anything triggered by a queue, a webhook, a cron, or a serverless function — all of which retry by default, often without telling you.

Probably not

A human clicking a button in a UI you control, where you can disable the button and show the result.

Errors

Both codes are documented in full on the Errors page.
  • 409 idempotency_key_in_flight — your first request is still running. Retry the identical request shortly; you will get the original result. Carries Retry-After.
  • 422 idempotency_key_reused — this key already means a different message. Use a new key.