Idempotency
Opt-in replay protection on the writes where a duplicate delivery costs something real.
Networks drop responses. When your create succeeded but the reply never arrived, the natural retry would make a second workflow, a second run. Idempotency-Key makes the retry safe:
curl -X POST "$BASE/api/workflows/$ID/run?environment=production" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: order-9137-attempt" \
-H "Content-Type: application/json" \
-d '{"orderId": 9137}'Retrying with the same key replays the original response — same run id, one run in the database — marked with the response header Idempotency-Replayed: true.
Where it applies
The writes where a duplicate causes real harm:
POST /api/workflows(create) and/api/workflows/importPOST /api/workflows/{id}/runPOST /api/workflows/{id}/duplicatePOST /api/workflows/{id}/webhook/rotatePOST /api/templates/{id}/usePOST /api/connections
Deliberately not on publish (already idempotent — the same version id comes back), on PUTs (they carry expectedRev), or on DELETEs (terminal).
The rules
| Rule | Behavior |
|---|---|
| Scope | Keys are scoped to the credential — two tokens can use the same key without collision. |
| Fingerprint | The stored record binds method + path + query string + body. The same key with a different request is refused 422 — a key can never replay the wrong write (environment=test vs production are different requests). |
| Lifetime | Results replay for 24 hours. |
| Concurrency | A retry racing the original waits briefly, then answers 409 — never a second execution. |
| Large responses | Stored responses are capped at 64 KB. An over-cap write is still deduplicated; its replay answers 409 naming the situation rather than faking an empty success. |
For agents
The MCP tools accept idempotencyKey as an argument on run-class calls for exactly this reason: a workflow-as-tool call that times out at the transport layer may have run, and only the agent knows its retry is the same logical attempt. See MCP → Workflows as tools.