A payment request times out. The client does not know whether the charge went through, and the customer is still waiting. Retrying blindly can charge the card twice; giving up can lose a sale that actually succeeded. Idempotency keys in a payment API solve this one problem: the client attaches a unique key to the request, and if it sends the same request again with the same key, the provider returns the first result instead of doing the work a second time.
Stripe, Adyen, PayPal and Square all support the pattern, but they differ on where the key goes, how long it lives and what happens when two copies arrive at once. Those details decide whether a retry is safe.
Why POST needs help
HTTP already defines some methods as idempotent. RFC 9110, the HTTP semantics standard, says PUT, DELETE and the safe methods such as GET have the same intended effect whether a request is sent once or several times. POST is not on that list, and creating a payment, a refund or a capture is almost always a POST.
A key turns that POST into something a client can repeat. Stripe’s documentation states it directly: all POST requests accept idempotency keys, while sending one with GET or DELETE has no effect because those requests are idempotent by definition. Adyen says the same for its POST endpoints.
An IETF working group drafted a standard Idempotency-Key header for exactly this use, but the Internet-Draft has expired without becoming an RFC. Each provider’s documentation is still the rulebook.
Four providers, four sets of rules
| Where the key goes | Length limit | How long it is kept | |
|---|---|---|---|
| Stripe | Idempotency-Key header | 255 characters | May be pruned after 24 hours |
| Adyen | idempotency-key header | 64 characters | At least 7 days |
| PayPal | PayPal-Request-Id header | 38 single-byte characters | Varies by API |
| Square | idempotency_key field in the request body | 45 characters on CreatePayment | Not stated on the general page |
Stripe saves the status code and body of the first request made with a key, whether it succeeded or failed, and returns that same result to later requests with the key, including 500 errors. It compares incoming parameters with the original and returns an error if they differ. Keys can be removed once they are at least 24 hours old; a key reused after that starts a new request. Stripe suggests V4 UUIDs and warns against putting email addresses or other personal identifiers in a key.
Adyen stores keys at the company account level and keeps them valid for at least seven days. A key used against one regional endpoint is not checked for duplicates in another region. Adyen recommends a random version 4 UUID per request partly for security: two API credentials under the same account could otherwise read each other’s stored responses.
PayPal uses its own header, PayPal-Request-Id, and its idempotency reference notes that not every API supports it; each endpoint’s reference states support and the retention period. One difference matters for reconciliation: PayPal returns the latest status of the earlier request, not a frozen copy of the original response. Omit the header and PayPal processes the request again. The value must be unique per request and per call type, so an authorization and its capture need different IDs.
Square puts the key in the request body. On CreatePayment idempotency_key is a required field of up to 45 characters. Square’s idempotency guide says a repeated request with the same key returns the first successful response, while the same key with a changed request, such as a different amount, returns an error, though behavior “might vary depending on the API.”
These are the providers’ current documented rules. For dated version changes and retirements by provider, see our payment API changelog tracker.
When two requests arrive at once
Retries are not always sequential. A client with an aggressive timeout can send a second copy while the first is still running.
Stripe does not save a result for a request that conflicts with another request already executing under the same key, so that request can be retried. Adyen answers a duplicate that arrives before the first has finished with HTTP 422 or 409 and error code 704, “request already processed or in progress.” When Adyen’s response carries a transient-error: true header, the request can be retried later with the same key; without it, Adyen says not to retry. PayPal says it processes the first of two simultaneous requests with the same ID and might fail the second.
Adyen also documents a rare failure of its own idempotency store, signaled by HTTP 503 with error code 703. Its advice is to pause and retry later or, if those errors pile up, to fall back to sending requests without the header.
Which errors to retry with the same key
Stripe’s advanced error handling guide sorts failures into three groups, and each calls for a different move.
- Network errors and timeouts. This is the case keys were built for. Retry with the same key and the same parameters until the server answers.
- Content errors (4xx). Fix the request and send it with a new key. A cached
400will keep coming back under the old key. Some 4xx responses, including429rate limits, are produced before the idempotency layer runs, but Stripe calls a new key the safest choice for any 4xx. - Server errors (500). Stripe caches these too, so the same key returns the same
500. It advises against switching to a new key because the first attempt may have had side effects, and it tells developers to treat the result as indeterminate and watch webhooks for objects created during reconciliation.
Both Stripe and Adyen recommend exponential backoff between retries. Stripe’s official libraries can generate keys and retry automatically once configured, and PayPal’s REST SDKs handle the header for you.
A short checklist
- Generate the key once per logical operation, before the first attempt, and store it with the order or payment record so a restarted worker reuses it.
- Use a random UUID. Never build keys from customer data.
- Reuse the key only with identical parameters. A changed amount is a new operation.
- Match the key’s lifetime to your retry window: a queue that retries after two days will outlive Stripe’s 24-hour minimum.
- Treat a key as protection for one request, not as reconciliation. Webhooks and a final status lookup still confirm what happened.
Adyen adds one more safeguard that keys do not replace: its accounting rules prevent capturing more than the authorized amount or refunding more than was captured, by default. A key prevents a duplicate request. It does not prove the first one did what you expected.
Questions readers ask
Do GET requests need an idempotency key?
No. Stripe says a key sent with GET or DELETE has no effect, because those methods are already idempotent.
Can I reuse a key with a different amount?
No. Stripe and Square both return an error when a reused key arrives with parameters that differ from the original request.
What should a client do after a timeout?
Retry with the same key and the same parameters, with exponential backoff, until the provider answers.
Sources
- RFC 9110, HTTP Semantics, Section 9.2.2: idempotent methods
- IETF Internet-Draft: The Idempotency-Key HTTP Header Field (expired)
- Stripe: Idempotent requests; Advanced error handling
- Adyen: API idempotency
- PayPal: Idempotency
- Square: Idempotency; Create payment
Documentation reviewed October 3, 2026.




