Idempotency
Every operation that moves money accepts Idempotency-Key. Send a key that is
unique per operation — your own transaction id works.
curl -s -X POST $BASE/v1/payouts \ -H "x-api-key: $KEY" \ -H "Idempotency-Key: payout-2026-0001" \ -H 'content-type: application/json' \ -d '{"quoteId":"70ec44b5-…","method":"pago_movil","beneficiaryId":"8ade3e33-…"}'What happens with each combination
Section titled “What happens with each combination”| Situation | Result |
|---|---|
| New key | It runs |
| Same key, same body | Returns the original response (same body, same HTTP code, with the Idempotent-Replayed: true header) without running again |
| Same key, different body | 409 idempotency_key_reused |
| The original is still in progress | 409 idempotency_request_in_flight — retry in a few seconds |
| The original failed | The reservation is released: you can retry with the same key |
{ "error": { "type": "invalid_request_error", "code": "idempotency_key_reused", "message": "Esta Idempotency-Key ya se usó con un payload distinto: usa una key nueva", "request_id": "req_8a0312ba896772bc441134cd" } }How it is compared
Section titled “How it is compared”The fingerprint is the method, the path with its query string and the
serialized body. Reordering the JSON keys counts as a different body, so
always serialize the same way. The key is isolated per program and per
mode: an sk_test_ and an sk_live_ key do not share keys. It only applies
to non-GET requests.
Secrets are not stored with the key. A gift card’s url, a newly created
apiKey or a rotated webhookSecret arrive only in the first response; when
repeating with the same key they arrive as null.
Windows
Section titled “Windows”| Key lifetime | 24 hours. After that, the same key is new again |
| Interrupted request | If a request is cut off without responding, the key can be reclaimed after ~60 seconds |
The second safeguard: the quote
Section titled “The second safeguard: the quote”The quote is single use: a second payout with the same quoteId gets
409 quote_already_consumed, even if you change the Idempotency-Key.
What to retry and with which key
Section titled “What to retry and with which key”| Response | Retry | Key |
|---|---|---|
502 upstream_error |
Yes | The same |
503 no_route_available |
Yes, later | The same |
429 rate_limited |
Yes, slower | The same |
| Timeout / dropped connection | Yes | The same |
Validation 4xx |
Not without fixing | New, because the body changes |
status: "failed" |
Yes, with another quote | New |
status: "unknown" |
Never | — |
See when something fails.