Timeouts in ecommerce integrations: preventing duplicate orders when retrying
Let's discuss your project →When a timeout happens, the real problem is not whether to retry. It is whether the system is retrying the same business action or creating a second order by mistake. Stripe’s documentation on idempotent requests explains how repeated requests can be treated as the same operation when the client reuses the same idempotency key and the request parameters match the original call. Stripe
The practical takeaway is simple: a retry should repeat an intent, not create a new one. Stripe states that POST requests can accept idempotency keys, that it stores the result of the first request for a given key even if that result is an error, and that it compares request parameters to prevent the same key from being reused with different data. It also notes that keys may be evicted after at least 24 hours. Stripe
Why this matters in ecommerce
A timeout does not tell you whether the remote system failed, succeeded, or completed the operation while the response was lost in transit. That ambiguity is where duplicate orders are created. If an application retries without a stable identity for the intent, the second attempt may be treated as a fresh order creation. If it never retries, a valid purchase may disappear from operations and customer support queues.
For teams connecting a shop to ERP, OMS, payment, or fulfillment systems, the safe model is to treat each order attempt as an application-level intention with its own stable identifier. That identifier should be generated by the client or orchestration layer, not derived from personal data. Stripe recommends high-entropy values such as UUID v4 or similarly random strings, up to 255 characters, and advises against using sensitive data such as email addresses or personal identifiers. Stripe
Simulated scenario: one order, one timeout, two retries
Simulated case for training purposes. A connector sends an order creation request to an external service. The network drops before the response arrives. The local system now has an uncertain state.
Prerequisites
- A stable idempotency key per purchase intent.
- A local record linking key, payload, external reference, and current status.
- A rule that distinguishes a repeated attempt from a genuinely new order.
- A reconciliation path for cases where the outcome is unknown.
Suggested procedure
- Create the key for the intent, not for the customer. The key should represent that specific order creation attempt and should not expose personal data. Stripe
- Store the payload together with the key. If the retry arrives with the same parameters, treat it as the same operation. If the parameters differ, it is no longer the same attempt and should be rejected or handled as a new business decision.
- Mark the state as known or uncertain. A timeout does not automatically mean failure. The remote service may already have created the order.
- Define reconciliation before adding retries. If the API supports lookup by reference, status checks, or another recovery path, use that before sending repeated calls.
- Respect the retention window. Do not assume the key will protect duplicates forever. Stripe notes that keys can be removed after at least 24 hours, after which a reused key can be treated as new. Stripe
Concrete input example
order_intent_id = "ord_20260921_1842"
idempotency_key = "2f6a1f0e-5e1a-4f4b-9d19-0d5d45e1b7f4"
payload = {
"cart_id": "C9821",
"amount": 149.90,
"currency": "EUR"
}
Expected output example
First attempt: request sent, response lost
Second attempt with same key and same payload: same outcome returned, no duplicate order created
Third attempt with same key but different payload: blocked as a mismatch
Fourth attempt with a new key: treated as a new business action
Acceptance checks
- Who checks: backend team. When: during development and pre-release. What to verify: same key + same payload does not create a second order.
- Who checks: QA or platform engineering. When: integration testing. What to verify: same key + different payload is rejected or flagged.
- Who checks: operations team. When: before go-live and after network incidents. What to verify: there is a documented reconciliation flow for uncertain orders.
- Who checks: security or backend lead. When: periodically. What to verify: keys are not reused beyond the expected retention window without an explicit decision.
Limits to state clearly
Idempotency is not a complete integration strategy. Stripe also notes that idempotent results are not always stored in every failure path: for example, validation failures and some concurrent conflicts are handled differently. The document describes Stripe’s API behavior, not a universal rule for all payment or commerce providers. Stripe
That distinction matters for any ecommerce platform that needs reliability under uncertainty. The correct design is not “retry until it works,” but “retry only when the system can prove it is repeating the same intent.” In practice, that means pairing a stable key with logging, reconciliation, and a clear boundary between a lost response and a brand-new order.
If you are mapping an order flow between shop, ERP, and external services, the first step is to identify where the response can be lost and where the system can still verify the outcome. That is the simplest way to avoid duplicate orders, manual cleanup, and support tickets that are more expensive than the original timeout.
Source consulted: Stripe documentation on idempotent requests, consulted on 2026-09-21. Stripe
