RailGuardDocs

Idempotency and retries

Why this beats a plain card limit.

Send idempotency_key in the body (or an Idempotency-Key header) on POST /api/public/transactions. Keys are scoped per agent.

RequestResult
New keyNormal evaluation, stored with the key
Same key + same amount, merchant, rail, recipient200 replay of the original decision, idempotent_replay: true. No new evaluation, no new card.
Same key + changed amount/merchant/rail/recipient409 IDEMPOTENCY_MISMATCH. Send a new key to get a new evaluation.
No keyEvery POST is a new evaluation
sequence
Agent            RailGuard            Approver
  | spend $250 (k1) |                     |
  |---------------->| flagged ----------->|
  |     202         |                     |
  | retry $250 (k1) |                     |
  |---------------->| replay, same txn    |
  |                 |<------- approve ----|
  |<-- webhook: approved, 1 card ---------|
  | spend $300 (k1) |                     |
  |---------------->| 409 mismatch        |
  | spend $300 (k2) |                     |
  |---------------->| new evaluation      |
Python
payment = guardrail.spend(amount=250, merchant="AWS", idempotency_key="order-8841")

Limits

  • A replay never returns the card secret again; it is handed out once. Poll the transaction for status.
  • A changed amount does not cancel a card already issued for the original request.
  • On 429, wait retry-after and resend with the same key.