Skip to content

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.

  • A 409 conflict 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_CONFLICT error.