Repeat a request without doing the work twice
The Idempotency-Key header — which requests require it, what a repeated request is answered with, and how to choose a key.
4 min read
A request that runs a flow or moves credits carries a key of your own in the Idempotency-Key header. The key names one piece of work. A request repeated under its key is answered instead of being done again, so a retry after a timeout or a lost connection runs nothing twice and charges nothing twice.
Where the key is required
The header is required by the requests that spend or move something:
a request that runs a flow —
POST /v1/operations/execute;a movement of a customer's credits —
POST /v1/customers/{externalUserId}/topup,POST /v1/customers/{externalUserId}/chargeandPOST /v1/customers/{externalUserId}/adjust.
The page of each resource marks these operations. The other operations do not read the header.
A request without the header, or with an empty one, is refused with
400and the codeidempotency_key_required. Nothing runs.A key is at most 190 characters. A longer one is refused with
422and the codeinvalid_request, before anything is held, charged or credited.
What a repeat is answered with
A repeat is the same request under the same key. What it is answered with depends on what the first request did.
| Request | A repeat under its key |
|---|---|
| A flow run | The execution the first request opened, as it is at that moment, with replayed set to true: 202 while the execution is not finished, 200 with its outcome once it is. Nothing runs again |
| A credit movement | The first answer, for 24 hours. After that, the account as it is now. The credits move once |
An answer with an error is kept in some cases and not in others.
A flow run keeps its key once the execution exists. An error that came before that —
flow_not_found, a body that fails validation — leaves the key free. An error that came after it, such asinvalid_flow_input, closes the execution, and a repeat reads it:200, the statusfailedand the code.A credit movement keeps only an answer that succeeded. A refused one can be sent again under the same key.
Another request under a used key
A key that already names a piece of work refuses another one. The answer is 409 with the code idempotency_conflict, and nothing runs.
{
"error": {
"code": "idempotency_conflict",
"message": "The Idempotency-Key was already used with a different request body",
"request_id": "6b2e9c4a-1d7f-4e3b-8a5c-0f9d2e7b4c61"
}
}What counts as another request depends on what the key names.
For a flow run, the body is compared byte for byte. Another input, another
context, anotherexecution_mode— even the same fields in another order — make another request.For a credit movement, any other body is another request while the first answer is kept. After that a credit movement is compared by its customer, credit type, kind and amount.
Choose a key
Make the key from the piece of work: an order and its step (
order-42:email), or the id of a job of your queue. Every repeat of that work then carries the same key, and the next piece of work gets a new one.A key made at random for each attempt protects only that attempt. A repeat your application sends under a new key is new work, and it is paid for again.
A key belongs to the project. Two projects may use the same key, and inside a project each piece of work has a key of its own.
To run the work again after a request failed — with another input or another model — send the corrected request under a new key.
Where to go next
Idempotency keys — the keys the SDKs send, and a key made from the job of a queue.
Operations — the request that runs a flow, and the model calls it made.
Error codes — what the codes of a refused key mean, and what to do about each.
Customers and credits — the keys of top-ups, charges and adjustments.
Quickstart — a first request with a key of its own.
Overview — the other conventions of a request.
Executions — read the execution a key belongs to, and its trace.