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.
| Request | Result |
|---|---|
| New key | Normal evaluation, stored with the key |
| Same key + same amount, merchant, rail, recipient | 200 replay of the original decision, idempotent_replay: true. No new evaluation, no new card. |
| Same key + changed amount/merchant/rail/recipient | 409 IDEMPOTENCY_MISMATCH. Send a new key to get a new evaluation. |
| No key | Every 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-afterand resend with the same key.