Payment Timeouts: Inquiry APIs, Async Flow and Idempotency
When checkout loses a payment response, three controls help teams recover the outcome and avoid duplicate processing: status inquiry, asynchronous updates and idempotency.
In this essay
A customer buys a pair of shoes. Their bank shows an authorization, but the checkout loses the response and displays "Payment failed." They try again. Support receives a screenshot showing two entries and no order confirmation.
The first request might have succeeded. The entries might be holds rather than settled charges. A timeout tells the merchant that it did not receive a response in time; the payment outcome still needs to be established.
Three controls help manage this situation: an inquiry API, asynchronous updates and idempotency. They address different parts of the problem. They do not eliminate network failures or guarantee that every payment completes.

What each control does
| Control | Question it answers | Boundary |
|---|---|---|
| Inquiry API | What status does the provider currently report for this payment? | A pending or unavailable result still needs follow-up. |
| Async flow | How will the merchant receive an update after the checkout request ends? | Events can arrive late, more than once or out of order. |
| Idempotency | Can a repeated request be recognized as the same operation? | Protection depends on the provider, endpoint, key scope and retention window. |
These controls should work against the same internal payment record. If inquiry results update one record while webhooks create another, the team still has an inconsistent order.
1. Inquiry API: recover the payment status
An inquiry API is a provider's payment retrieval or status-query interface. For example, Stripe exposes a retrieve endpoint for an existing PaymentIntent. The response includes the object's current status. Other providers use different identifiers and status models. Stripe PaymentIntent retrieval
Save the merchant order reference and any provider payment identifier as early as possible. After a timeout, query the original payment using the identifiers and account context supported by that integration.
There is a practical complication: the initial response might be lost before the merchant receives a provider identifier. Establish in advance whether the provider supports lookup by a merchant reference or recovery through the original idempotent request. Do not assume every provider offers both.
My recommended inquiry policy records:
- the identifier and provider account used for lookup;
- which statuses permit fulfillment, require customer action or remain unresolved;
- the next check time and maximum automatic checking period;
- the owner who investigates when the outcome remains unknown.
A temporary "not found" response should be interpreted against the provider's documented consistency and timing behavior. Avoid converting it automatically into permission to create another payment.
2. Async flow: accept updates after checkout
A payment can change state after the customer's HTTP request has finished. An asynchronous design lets the provider notify the merchant separately, usually through webhooks or callbacks.
Stripe documents duplicate event delivery, possible out-of-order arrival and webhook signature verification. It also recommends asynchronous processing through a queue. These are concrete integration requirements, not reasons to assume every provider behaves identically. Stripe webhook guidance
For a merchant implementation, I would use a durable inbox:
- Verify the notification using the provider's documented authentication method.
- Persist the accepted event before acknowledging it, within the provider's response deadline.
- Process it through a worker that can recover after a crash.
- Update the existing payment and order records using guarded state transitions.
- Record the processing outcome so replay does not repeat the business action.
Deduplicating an event identifier is useful, but the order also needs protection. Two different events can both describe a payment that is ready for fulfillment. An atomic order transition or equivalent business constraint should prevent two shipments.
Use provider-specific rules when notifications and inquiry results disagree. Do not let an older event overwrite a later confirmed state simply because it arrived last. Fetch the current payment object or send the conflict to an exception queue when necessary.
3. Idempotency: recognize the same operation
An idempotency key identifies a logical operation across repeated API requests. Create and store it before sending that operation. If a supported retry is needed, reuse the key with the same request parameters.
For Stripe API v1, the documented behavior includes replaying the original status and response after execution begins, including certain error responses. Parameter mismatches are rejected, and keys may be removed after at least 24 hours. These details are specific to that API version. Stripe idempotent requests
Adyen documents a different scope and retention policy: keys are checked at company-account level, retained for 7 to 14 days, and are not deduplicated across separate regional endpoints. Its transient-error guidance determines when retry is appropriate. Adyen API idempotency
Build a short contract for each provider rather than assuming one policy fits every gateway:
| Contract field | What to establish |
|---|---|
| Supported operation | Which create, capture or refund endpoint accepts a key? |
| Scope | Does deduplication apply per account, region or another boundary? |
| Parameters | Which fields must remain identical on a retry? |
| Lifetime | How long does the provider retain the key? |
| Error behavior | Which results are replayed, retryable or indeterminate? |
| Concurrency | What happens when two requests with the same key arrive together? |
Do not generate a new key merely because a request timed out. A capture and a refund are separate operations and need separate identities. Two intentionally different partial refunds also need distinct identities.
A provider's key does not automatically protect a request routed to another provider. Resolve the original attempt before considering a second route, using an explicit orchestration policy.
A recovery example
This is an illustrative design sequence, not a universal gateway protocol:
- The merchant creates an internal payment record and stores the operation key before sending the request.
- The connection times out. The merchant records the outcome as unknown and shows "We're checking your payment. Please don't retry yet."
- A background worker uses supported inquiry or same-key recovery. Retry delays, limits and error handling follow the provider's contract.
- A verified asynchronous update arrives. The worker joins it to the existing payment record and applies the permitted state transition.
- The order is fulfilled only when the payment reaches the state required by the merchant's capture and fulfillment policy.
- If automatic recovery ends without a reliable outcome, an operator owns the exception and updates the customer.
Repeated retries can worsen an incident. Stripe's error-handling documentation distinguishes network failures, invalid requests and indeterminate server errors. Retry logic should respect those distinctions rather than treating every non-success response the same way. Stripe error handling
What to test before launch
| Scenario | Expected evidence |
|---|---|
| Provider accepts payment but the response is lost | Original operation remains traceable; recovery does not create another payment. |
| Customer double-clicks or two workers submit concurrently | One logical operation is enforced through durable concurrency controls. |
| Inquiry API is unavailable | Customer sees a pending state; bounded follow-up and an exception owner are recorded. |
| The same webhook arrives twice | The repeat is recognized; fulfillment and ledger effects are not repeated. |
| Events arrive out of order | State remains consistent with the provider's documented lifecycle. |
| A worker crashes after accepting an event | Durable recovery resumes processing without losing the update. |
| A key is reused with changed parameters | The mismatch is rejected or handled explicitly, without a new charge. |
| The provider's key-retention window expires | Old uncertain work is reconciled before any new operation is allowed. |
| Routing proposes another provider | The unresolved original attempt blocks blind failover. |
Keep the test receipts, payment references and resulting order states. A test passes when the records show the expected behavior, not merely when the screen looks correct.
Give support the same payment history
Support should be able to see the order reference, each operation, provider identifiers, latest status, last inquiry, verified updates and the next action. Restrict access and redact sensitive credentials from logs.
Keep authorization, capture, refund and settlement statuses distinct. Confirming an authorization does not prove merchant payout. A refunded order also needs a traceable refund operation, not just a note that support promised money back.
This is where reconciliation and exception management connect to the checkout. The customer should not have to reconstruct the payment history for each team.
FAQ
Does idempotency prevent payment timeouts?
No. It helps a supported API recognize a repeated operation. Inquiry and asynchronous updates help recover the outcome when the original response is missing.
Can an inquiry API replace webhooks?
It can provide status on demand where supported. Webhooks provide updates without continuous polling. Using both gives a recovery path when one is delayed or unavailable.
Is an idempotency key enough to guarantee one shipment?
No. Provider request deduplication and merchant fulfillment are separate boundaries. The order workflow needs its own durable constraints and recovery handling.
Do MPGS and Cybersource follow the same retry rules as Stripe?
Do not assume they do. Confirm the exact gateway product, API version, supported inquiry operation and duplicate-handling contract with your provider. A tokenization service such as MDES is a separate concern from API request idempotency.
When should the customer be asked to try again?
When the original outcome has been resolved and the provider and merchant policies allow another attempt. An unknown result alone is not enough evidence.
Closing thought and further reading
When checkout loses a payment response, three controls help teams recover the outcome and avoid duplicate processing: status inquiry, asynchronous updates and idempotency.
Building through similar complexity?
Discuss the operating decisions behind the essay, or explore where my experience can help.


