Idempotency for Gift Card Orders: One Retry Can Cost Real Money

· updated

An idempotency key makes a retried API request safe: you send the same unique key with the retry, the provider recognises the order has already been processed, and it returns the original result instead of issuing a second code. Without one, a single network timeout can turn into two purchased codes for one paid customer.

Most payment engineers know the pattern. What changes with gift cards is the price of getting it wrong, because the thing you accidentally buy twice cannot be un-bought.

Why a duplicate order is money gone

A gift card code is a bearer instrument, and ordering one is an irreversible purchase. There is no void, no refund window, no chargeback: the moment the provider issues the code, it is sold, whether or not you meant to order it. A duplicate card payment gets reversed with an apology; a duplicate code order is money spent twice with one sale to show for it.

At low volume this is an annoyance you eat. At scale it compounds quietly, and it tends to cluster exactly when your infrastructure is having a bad day, which is when retries fire most. That asymmetry is why idempotency belongs in the first version of a gift card API integration, not in the hardening sprint.

What an idempotency key is

An idempotency key is a unique value, generated by you, attached to one logical order: one customer, one product, one purchase intent. You store it with the order record before sending the request. If the request must be sent again, it goes out with the same key, and the provider treats the repeat as a lookup rather than a new purchase, returning the code it already issued.

Two rules make the pattern hold. The key belongs to the logical order, not to the HTTP attempt, so every retry of the same order reuses it. And it must be persisted before the first attempt: a key that lives only in memory dies with the process that crashed mid-request, taking your proof of the first attempt with it.

The timeout trap

Here is the failure that catches teams. Your checkout sends an order request. The provider receives it, buys the code, and starts sending the response. The connection drops before the response reaches you. From your side this is a timeout, indistinguishable from a request that never arrived.

A timeout is not a failure; it is an unknown outcome. The natural reaction, send it again, is exactly wrong without a key: the provider sees a second, unrelated order and fills it. With the key, the retry is harmless, the provider matches it to the completed order and hands back the original code. The customer waits two extra seconds and nobody notices anything happened.

A safe retry policy

  • Retry with the same idempotency key, always. A fresh key on retry is a fresh order.
  • Use bounded backoff: a few attempts over a couple of minutes, with growing gaps. Endless retry loops turn provider incidents into your incidents.
  • Distinguish error classes. A definitive rejection (invalid product, insufficient balance) is final, so do not retry it; only timeouts and transient errors qualify. The full taxonomy is in gift card API order failures.
  • When the retry budget is spent, stop and mark the order unresolved. Query the provider for the order’s status by your key or reference, and let reconciliation catch anything that slips through: a daily comparison of your order log against the provider’s invoice is where silent duplicates surface.

Prove it in the sandbox

Every serious provider’s sandbox lets you rehearse this before real money is involved. Three tests are worth writing: send the same order twice with the same key and assert you get one code; kill the connection mid-request and confirm your retry recovers the original result; crash your own process after persisting the key and check that the restarted worker resumes the order rather than starting a new one. If any of the three fails in the sandbox, it is already failing in production, just less visibly.

Frequently asked questions

What is an idempotency key?

An idempotency key is a unique value the client attaches to an API request so the server can recognise a retry of the same operation. If the request is sent again with the same key, the server returns the original result instead of executing the operation twice. For gift card orders this means a retried purchase yields the already-issued code, not a second one.

Should I retry a timed-out gift card order?

Yes, but only with the same idempotency key the first attempt used. A timeout means the outcome is unknown: the provider may have completed the purchase before the connection dropped. Retrying with the same key safely resolves either case, while retrying without one risks buying a second code. After a few backed-off attempts, stop and query the order’s status instead of continuing to retry.

What happens if I order without an idempotency key?

Every request the provider receives becomes a separate purchase. In the happy path nothing goes wrong, which is why the gap survives testing. The first production timeout plus an automatic retry then buys two codes for one customer, and since delivered codes are not returnable, the second one is an unrecoverable loss found at reconciliation, if it is found at all.

How do I generate an idempotency key for an API order?

Generate one unique value per logical order, a UUID works well, and store it on the order record before the first request goes out. The key belongs to the purchase intent, not the HTTP attempt: every retry of that order sends the same key, while a genuinely new order gets a fresh one. A key that lives only in memory is a key you lose in a mid-request crash.

Do idempotency keys expire?

Often, yes: many providers guarantee deduplication only within a bounded window, after which a reused key may be treated as a new order. The window varies by provider, so check the documentation and resolve unknown-state orders promptly rather than leaving retries for days. In practice a sound retry policy finishes within minutes, well inside any sensible window.

All product and company names are trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them; Giftoro is an independent distributor.