Idempotency¶
Networks fail after a request is sent but before the response arrives. Idempotency is how you retry a write safely: the same key never moves money twice.
The contract¶
Every money-moving command carries an idempotencyKey field in the request body (not an HTTP
header). Set it on every write:
{
"idempotencyKey": "payroll-2026-07-run-1",
"fromAccount": "1000200030",
"toAccount": "1000200048",
"amount": { "amount": 250.00, "currency": "USD" }
}
The guarantee is exactly-once ledger effect, at-least-once delivery:
- First call with a key executes and records the outcome against it.
- A replay with the same key returns the original result. It does not post again.
- The same key with a different payload is a conflict, and is rejected: never a silent double-post.
Because the effect is deduplicated at the ledger, you can retry a timed-out request as many times as you need with the same key and be certain the money moved once.
Choosing keys¶
- Make them meaningful and unique per logical operation:
payroll-2026-07-run-1,invoice-88213-settlement. A UUID per attempt-set works too. - Never reuse a key for a different operation. The key identifies this business action; reusing it for another will either return the wrong original result or raise a conflict.
- Keep the key for the whole retry window of one operation, so every retry carries it.
Rail identifiers map to the key, they don't replace it¶
Rail-native identifiers (the ISO 20022 endToEndId, a SWIFT uetr, a card stan+rrn, a document
content hash) map onto your idempotency key for end-to-end tracing. They are unique references,
but the business deduplication is still done on idempotencyKey. Send your own key even when a rail
id exists.
Related failure modes¶
- A
409conflict on a write usually means a concurrent change to the same record (an optimistic-lock clash), not an idempotency replay. See Errors. Re-read and re-apply. - On the agent gateway, a same-key-different-args reuse surfaces as a typed
IDEMPOTENCY_CONFLICTerror.