Idempotency
Calls that move money or create a session need an Idempotency-Key header:
| Call | Header |
|---|---|
POST /v1/payments |
required |
POST /v1/payments/{id}/refunds |
required |
POST /v1/payments/{id}/reprocess |
required |
POST /v1/checkout-sessions |
required |
POST /v1/refunds/bulk, POST /v1/payments/reprocess |
one key per item in the body |
Rules:
- 8 to 255 characters of
A-Z a-z 0-9 _ - : .(400 idempotency_key_requiredotherwise). - Derive it from your own data, for example
order-1042-pay-v1orrefund-1042-1, and store it before you call. Never generate a random key per retry: the point is that a retry sends the same key. - Same key and same request: GIEP returns the original result and never repeats the side effect. This holds even if
the first request is still running elsewhere: you get
409 request_in_progress; retry a little later. - Same key with a different body:
422 idempotency_key_reused. - A request refused by validation (4xx before anything was sent to a processor) releases the key, so you can fix the body and retry with the same key.
POST /v1/checkout-sessionsreplays return the same session with a freshly issued token (the token itself is never stored in clear).- Refund keys are per refund: the same key for a different payment or amount is
422 idempotency_key_reused. Keys starting withalert:are reserved.
A timeout is not a decline. If a money call times out or the connection drops, you do not know whether it worked. Retry with the same key, or read the payment. Never create a second payment with a new key for the same order.