It is your protection against sending the same email twice.
The problem it solves is a normal fact of networking: A request can succeed on the server and still look like a failure to the caller. The connection drops while the response is coming back, a timeout fires, a queue redelivers a job, a deploy restarts a worker mid-request. Your system knows that it sent the call; it does not know whether Automations acted on it. The safe-looking move (retry) would send the customer a second order confirmation.
The idempotency key removes that dilemma. Automations stores the key alongside the workflow run it created. On every call, it checks whether a run already exists for that key in that workflow:
| Situation | Response | What happens |
|---|
| First call with this key | 201 with {"workflow_run_id": "…", "created": true} | A run starts, the email is sent. |
| Same key again | 200 with {"workflow_run_id": "…", "deduplicated": true} | Nothing happens; you get back the ID of the original run. |
So retrying is always safe, and a retry is indistinguishable from the original call as far as the customer is concerned. Retry until you get a 2xx; that’s the whole point of the mechanism.
Choosing the value
The key must identify the event, not the attempt. The question to ask is: “if this value were computed twice, would the answer be the same?”
| Value | Verdict |
|---|
order-42-shipped | ✅ Derived from the order and what happened to it |
password-reset-user-77-2026-09-21T10:15:00Z | ✅ Reset requests repeat, so include the moment |
booking-9931-reminder-24h | ✅ Names which of several emails about one booking this is |
uuid4() generated per attempt | ❌ Every retry is a new event which switches deduplication off |
| Current timestamp | ❌ Same problem |
order-42 | ❌ Too coarse as it blocks the shipping email if the confirmation used it |
Any string works; there are no format restrictions. A useful convention is <entity>-<id>-<what happened>.