The problem
Consider a “create payment order” request that returns a network error:- Did the server receive the request and process it? → Retry creates a duplicate payment.
- Did the request fail before the server saw it? → Not retrying leaves you with a missing payment.
The solution: idempotencyKey
When you create a payment order, supply an idempotencyKey — a client-generated identifier unique to the intent of the operation:
(wallet, idempotencyKey) tuples:
Retries become safe. You can retry as many times as needed without creating duplicates.
Choosing an idempotencyKey
Tie the key to the business intent, not the network attempt.
The persist-then-call pattern
The safest implementation:1
Persist the intent locally
Before you call the API, write a row in your database describing the operation, with a stable
idempotencyKey (UUID v4 is fine).2
Call the API with that key
Include the persisted key in the request body.
3
On any error
Retry — read your persisted key from the local row, do not regenerate.
4
On success
Update your local row with the returned
id and current status.Scope and lifetime
Because keys are retained indefinitely, scope them carefully.
payment-1 is a poor key — it will collide eventually. Prefix with a meaningful namespace: invoice-2026-0184.When you supply different params on retry
The most common cause ofIDEMPOTENCY_KEY_IN_USE_WITH_DIFFERENT_PARAMS is not a bug in your retry logic — it is reusing a key across different invoices.
If you genuinely need to retry with corrected parameters (e.g., the original amount was wrong):
- Treat the original key as burned.
- Mint a new
idempotencyKeyfor the corrected attempt. - Reconcile against the original key via your local persistence.
What if I do not supply an idempotencyKey?
The OpenAPI spec marks idempotencyKey as optional. Omitting it means every retry creates a new order. For PIX in particular this means every retry potentially creates a duplicate payment.
What is NOT idempotent
For
approve and cancel, the operation is idempotent in effect — calling twice does not duplicate the state transition; the second call merely returns an error indicating the resource is no longer in the right state. Treat the error as success when you know you intended the transition.
Idempotency vs request retry signature
Each retry attempt still needs a newX-Access-Request-Id — that is the signing protocol’s anti-replay nonce, separate from idempotencyKey:
See Sign a request for the request-id rules.
Next
Retry strategy
When to retry and how to back off.
Payments overview
How idempotency interacts with the payment-order lifecycle.