Rule of thumb
- Same idempotency key = same payment attempt (safe retries, no duplicates)
- New idempotency key = new payment attempt (creates a new payment)
IDEMPOTENCY_KEY_ALREADY_EXISTS.
How it works
In Auto flow, the SDK creates the payment by calling the Payments API internally. When you provide an idempotency key, the SDK includes it as theX-Idempotency-Key header on:
POST /payments(create payment)
- The API will not create a second payment.
- It will fail with a
409 Conflictresponse.
Why key rotation matters
For redirect and 3DS flows, the payment is created before the user completes the external step. If the user abandons the redirect or retries after a failed authentication, this becomes a new payment attempt, and the key must be rotated. If you do not rotate the key, the retry will fail with an error codeIDEMPOTENCY_KEY_ALREADY_EXISTS
When to reuse vs rotate
Reuse the same key
Reuse the current key when you are retrying the same attempt, for example:- transient network retry
- the SDK retries the same request
- resume of the same attempt
Rotate the key
Rotate to a new key when the user starts a new attempt, for example:- user abandons a redirect or popup flow and tries again
- user cancels the payment and tries again
- failed 3DS and the user retries as a new attempt
- user switches payment method (optional but recommended)
Recipe
In this recipe we:- Intercept payment creation with
primer:payment-start - Provide an
idempotencyKeyper attempt - Rotate the attempt when the user abandons a redirect flow using
primer:payment-cancel - Handle duplicate key errors explicitly
Example
Handling network loss and page refresh
Idempotency prevents duplicate charges, but it does not fully manage recovery when the client loses state. If the network drops or the page refreshes right aftercreatePayment is sent:
- The payment may have been created on the server, even if the client never received a response.
- Retrying with the same idempotency key is the safest client-side action for the same attempt.
- If the client lost state, it cannot reliably know if the payment succeeded, is pending, or failed.
- Keep a server-side order state, and/or
- Listen to webhooks, and/or
- Use manual payment flow for full lifecycle control.
Common pitfalls
Rotating the key on every click
If you generate a new key every time, you reduce the protection against true request retries.Reusing the same key after abandon
If the user cancels a redirect flow and tries again with the same key, the API will fail with a409.
Treating idempotency errors as generic failures
IDEMPOTENCY_KEY_ALREADY_EXISTS is often expected behavior.Handle it explicitly and guide the user instead of showing a generic error.