Technical

Idempotency key

Idempotency key — guarantee that an API request runs exactly once

A mechanism by which a client sends a unique identifier with a mutating API request (POST), ensuring that on a network retry the operation will be executed only once on the server side. A critical best practice for payment APIs.

Definition

The idempotency key is a unique identifier that a client sends with a mutating request (typically a POST) to ensure that, on a network retry, the operation will be executed only once.

The server stores the key; if the same request comes back, it returns the previous response without replaying the operation. It is a critical best practice for any payment API, where a double execution means a double payment, double billing or corrupted state. Stripe, Bridge, Adyen, Mollie, AWS and many others require or support it.

Why it is critical

On the network, uncertainty is the rule: a request can time out without your knowing whether it was received, processed, or whether a retry will duplicate the operation. Without an idempotency key, you cannot retry safely; with one, the client can retry with confidence, and the server returns the stored response if the operation has already happened.

How it works

Format and best practices

  • Generation: UUID v4 (random), ULID (time-sortable, debug-friendly), or a deterministic business hash (SHA256(user_id + transaction_ref)).
  • Header: Idempotency-Key: 4a7f3b80-fe5c-4d12-9c7e-83b3a4ab9b1c. The IETF has published a draft, but the convention was adopted well before it was made official.
  • Cache duration: 24h at Stripe and Bridge, 1h at Mollie. Recommended: 24 to 48h for payments, 7 to 30 days for asynchronous flows. Beyond that, a retry would replay the operation.
  • Scope: per merchant / per account (recommended), rather than global (collision risk).

Different payload, same key

If the same key is sent with a different payload, the server should reject the request (409 Conflict), as Stripe and AWS do. This prevents a payment €200 from being silently ignored after a payment €100 carrying the same key.

Use cases

  • Payments: POST /payments, /transfers, /charges, /refunds — always.
  • Resource creation: POST /customers, /subscriptions — to avoid duplicates.
  • Expensive operations: POST /kyc, /loans/disburse.
  • Unnecessary on: GET (idempotent by nature), PUT with an explicit ID, DELETE.

Idempotency-Key vs other techniques

TechniqueGuaranteeComplexity
Idempotency-Key (header)Exactly-once per callLow on the client side
Unique transaction tokenExactly-once per business transactionMedium
Optimistic DB lockExactly-once per resourceMedium
Saga + commandsExactly-once per flowHigh

The Idempotency-Key works at the API level: it does not protect against a business bug (a user who pays twice via two different buttons generates two distinct keys).

Server-side implementation

Typical storage: Redis (native TTL, key idempotency:{merchant}:{key}), DynamoDB for scalability, or PostgreSQL at low volume.

def handle_payment(req):
    key = req.headers.get("Idempotency-Key")
    if not key:
        return create_payment(req)
 
    cached = redis.get(f"idempotency:{merchant}:{key}")
    if cached:
        return cached
 
    with redis.lock(f"idempotency-lock:{merchant}:{key}", ttl=30):
        cached = redis.get(f"idempotency:{merchant}:{key}")
        if cached:
            return cached
 
        response = create_payment(req)
        redis.setex(f"idempotency:{merchant}:{key}", 86400, response)
        return response

The lock is necessary if two requests carrying the same key arrive at the same time (a retry race condition), to avoid a double execution in parallel.

Behavior on failure

  • Client timeout, server success: retry with the same key → cached response (success).
  • 5xx error: most providers replay (a 5xx is not considered final).
  • 4xx error: retry with the same key → the cached 4xx response is returned.

What the Idempotency-Key is not

  • Not a distributed transaction: it does not guarantee cross-service consistency.
  • Not a business safeguard: two clicks on two buttons generate two keys.
  • Not a replacement for authentication: it is complementary.
  • Not required on GET / PUT: natively idempotent.
  • Not (yet) a formal standard: an IETF draft, but a near-universal convention.

In the PSD2 / Open Finance ecosystem

  • Berlin Group: recommends X-Request-ID (equivalent).
  • STET: the X-Request-ID header.
  • OBIE UK: x-idempotency-key.
  • Acquiring PSPs (Stripe, Adyen, Mollie): universally adopted.
  • Webhooks: the key is also crucial on the receiving side, so as not to process the same event twice.

Concrete examples

  • Stripe: the Idempotency-Key header, a 24h cache, rejection of a different payload — the industry standard.
  • Bridge: Idempotency-Key + X-Request-ID depending on the endpoint.
  • Mollie: Idempotency-Key, a 1h cache.
  • AWS: the client-token parameter.
  • Real-world case: a merchant without an idempotency key retries after a timeout → double debit on 0.5% of payments → tens of thousands of euros in refunds and lost trust.
  • UI pattern: generate the key on click and persist it in the form state — a re-click 5 seconds later reuses the same key, with no double charge.

Sources

Go deeper

From the blog

Longer reads to go beyond the definition.

August 24, 2026
security

QWAC vs QSealC: who does what, and why you've got the wrong layer — Read more

The QWAC is read by the TLS layer, once, at the handshake. The QSealC is read by the application layer, on every request. Where each private key lives, what STET requires, and how to read a 'certificate error'.

April 7, 2026
technical

Technical architecture of a PSD2 API: what to know before writing the first line of code — Read more

A technical overview of PSD2 for CTOs, developers and technical PMs: API standards, security (mTLS, eIDAS certificates), OAuth2, SCA flows, consent management, implementation pitfalls.

April 6, 2026
regulation

Understanding PSD2: what it changes for your customers and your business — Read more

Everything an executive, a product manager or a business team needs to understand about PSD2. Players, consent, opportunities, without technical jargon.