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 400 will keep coming back under the old key. Some 4xx responses, including 429 rate 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

Documentation reviewed October 3, 2026.