Chat

Idempotency Keys for Payments and Order APIs

The invisible reliability layer behind checkout: idempotency keys, replay protection, webhook dedupe, and exactly-once side effects for payment and order APIs.

Customers never ask about idempotency keys. They ask why they were charged twice. Idempotency is invisible development work that protects money, inventory, and trust.

At ShubhKarma Tech we treat checkout, booking holds, and webhook consumers as systems that will retry — because networks retry whether you like it or not.

What idempotency means in practice

The same logical operation, applied once or many times, leaves the system in the same state. `POST /orders` with the same key must not create two orders. A payment capture retry must not capture twice.

Where retries come from

- Client double-submit (button mashed)

- Mobile app replay after timeout

- API gateway retries

- Queue at-least-once delivery

- Payment provider webhook redelivery

If your handler is not idempotent, every retry is a landmine.

Client idempotency keys

Require a header such as `Idempotency-Key` on creating operations. Persist key → response (status, body, resource id) in a durable store with a TTL window (for example 24 hours).

Algorithm:

1. Lookup key for this API key / tenant.

2. If in-progress, return 409 or a wait signal.

3. If completed, return the stored response.

4. Else lock, execute, store, unlock.

Keys must be scoped per tenant so two customers cannot collide.

Database patterns that help

- Unique constraint on `(tenant_id, idempotency_key)`

- Unique payment `provider_payment_id`

- Order numbers generated server-side, never guessed by clients

Application checks without unique constraints will race under concurrency.

Webhook dedupe

Providers redeliver. Store processed `event_id` values with a unique index. Process handlers as:

1. Insert event id (fail if duplicate).

2. Apply side effects in a transaction where possible.

3. Mark complete.

If side effects cannot be transactional (email, SMS), make those consumers idempotent too.

Exactly-once vs at-least-once

Most infrastructures are at-least-once. Exactly-once side effects are achieved by idempotent handlers plus dedupe keys — not by hoping the broker delivers once.

Testing checklist

- Replay the same key 100 times → one order

- Parallel requests with one key → one order

- Webhook redelivery → one inventory decrement

- Timeout after commit but before response → client replay returns original order

Final takeaway

Idempotency keys are invisible to shoppers and hotel guests. They are mandatory for anyone building payment or order APIs that must survive retries without double side effects.

Frequently asked questions

Who should generate the idempotency key?

The client for user-driven creates (browser/app). For webhooks, use the provider event ID. For internal jobs, use a deterministic key from the job payload.

How long should we store idempotency records?

Long enough to cover realistic retries — often 24–72 hours for payments. Keep unique provider IDs permanently.

Are GET requests idempotent by default?

They should be. Never make GET mutate state. Puts/patches need careful design; creates need explicit keys.

Does Stripe-style idempotency apply to my custom API?

Yes. The same key-replay pattern works for any create operation with side effects.

Related links

Back to Blog