Payments tools / Payment retry simulator

What happens when you retry a payment?

A timeout tells you that the response did not arrive. It does not tell you whether the payment was created. Explore what changes when a retry uses the same key, a new key or different payment details.

Synthetic exercise. No money moves. Scenario playback runs in your browser. This is an educational reference model, not a live API client, a conformance test of any provider or a settlement record.

Step through a scenario

The interactive simulator is not running. It needs JavaScript and may also be blocked by your browser or network. Every scenario still works as a worked example: see what each scenario demonstrates for the steps, totals and lessons.

What each scenario demonstrates

Every scenario begins with nothing sent and one intended €30.00 order (order-demo-001, payee supplier-demo). Create requests include any lost before reaching the provider; status lookups and webhook deliveries are not create requests. The completed total is simulated, not settlement evidence.

Seven V1 scenarios and the outcomes the model must reach
ScenarioStepsCreate requestsProvider recordsCompleted totalFulfilmentsLesson
R01 Lost response, same-key retryProvider creates P1 for key-A; the response is lost. Retry key-A with identical details; the cached 201 returns P1. P1 completes; success event E1 arrives.21€30.001The same key and details recover the original payment. One payment, one fulfilment.
R02 Lost response, new-key retryProvider creates P1 for key-A; the response is lost. Retry as submission-B with key-B; the provider creates P2. Both complete. P2’s success arrives, then P1’s.22€60.001A new key is a new payment. The order is fulfilled once, but two payments totalling €60.00 now need review.
R03 Request lost before the providerThe first key-A request never reaches the provider. Retry key-A with identical details; the provider creates P1. P1 completes; its success arrives.21€30.001The application sees the same timeout as in R01, although the provider holds nothing. A same-key retry is safe either way.
R04 Same key, changed amountProvider creates P1 for key-A at €30.00; the response is lost. Retry key-A at €35.00: 409 conflict. Retry key-A at the original €30.00: P1 is returned. P1 completes; its success arrives.31€30.001A conflict creates nothing, keeps the original binding and does not mean the original payment failed.
R05 Duplicate webhook deliveriesRecover P1 by same-key retry; P1 completes. Event E1 is delivered three times, then a distinct event E2 reports the same success.21€30.001Event IDs catch repeat deliveries; order state catches a different event about the same result.
R06 Older event arrives lastRecover P1 by same-key retry. A processing event E1 is generated and held; P1 completes (E2). E2 arrives, then the older E1.21€30.001The late processing event triggers a current-status lookup, which still says succeeded. No rollback.
R07 No webhook: retrieve statusRecover P1 by same-key retry. P1 completes, but no event is delivered. The application retrieves P1 by the ID it already knows.21€30.001Until the retrieval, the provider has succeeded but the application still says processing and fulfils nothing.

Why a timeout is not a failure

When a create request times out, the application cannot tell whether the request was lost on the way out (R03) or the provider created the payment and the response was lost on the way back (R01). Its knowledge is identical in both cases. Treating the timeout as a failure and releasing the order, or sending a fresh request, can produce a second payment.

The safe move is to keep the original submission unresolved and ask again in a way the provider can recognise: the same idempotency key with exactly the same details. In this model the provider then returns its cached original 201 response, even if the payment has since moved on. A current status needs a separate lookup.

Same key, new key or changed details

  • Same key, same details (R01, R03): the provider recognises the retry. One payment.
  • New key (R02): the provider sees a new request. It does not deduplicate on the order reference alone, so the order now has two payments. The first submission stays unresolved until evidence about it arrives; learning about the second says nothing about the first.
  • Same key, changed details (R04): the key is bound to the order, submission reference, amount, currency and recipient. A changed amount is refused with a conflict that creates nothing and leaves the original binding intact.

Real providers differ in key scope, which fields are compared and how long keys are kept. Stripe, for example, documents that it saves the status code and body of the first request for a key, compares later parameters with the original and may remove keys once they are at least 24 hours old: Stripe idempotent requests. Check the contract of the provider you integrate with.

Duplicate, late and missing webhooks

A webhook can arrive more than once, out of order, or not at all. In this model the application records each processed event ID and acknowledges a repeat without effect (R05). For each new event it looks up the payment’s current status before acting, so an older event cannot roll back a confirmed payment (R06). Fulfilment is applied at most once per order, so a second event describing the same success does nothing more.

When no event arrives, the application stays unconfirmed until it retrieves the payment by an ID it has already learned (R07). It cannot look up a payment whose ID it never received. That is why the lost-response scenarios recover the ID first. Stripe’s documentation describes the same practical concerns: events are not guaranteed to arrive in order, and the same event, or two separate events, can be received for one change.

Model assumptions and limits

The nine assumptions behind every scenario
  1. The illustrated provider supports atomic, scoped idempotent creation and keeps each key for the whole exercise. It does not deduplicate a second key because the order reference is the same.
  2. The key scope is the merchant, the create-payment operation and the key. The key binds the order, submission reference, amount, currency and recipient; property order does not matter.
  3. Creation returns a cached 201 response with a provider payment ID and the processing state. Exact replay returns that original response. Changed details return a synthetic 409 without creating a record or changing the binding.
  4. Payments move from processing to succeeded, adding to the simulated total exactly once. These labels are not bank settlement evidence or a mapping to every provider status.
  5. Every payment created in these scenarios eventually succeeds. Failures, cancellations, refunds, key expiry, concurrent in-flight requests and partial captures are outside V1.
  6. A status lookup needs a provider payment ID learned from a response or an authenticated webhook.
  7. Webhooks are trusted synthetic inputs with an event ID and payment ID. Each new event triggers a status lookup before the application updates its record. No signature verification is modelled.
  8. Provider status includes the synthetic order and submission references, so a previously unseen payment can be matched to its order.
  9. Fulfilment happens at most once per order, after a current successful payment whose amount, currency and recipient match. A second successful payment is flagged for review; it does not trigger a second fulfilment or an automatic refund.

The downloaded JSON trace includes these assumptions. It demonstrates the reference model only; it is not an audit receipt, certification or a ZILLQ API test result.

Go from model to exploration

Explore payments in the ZILLQ sandbox.

The sandbox is a separate synthetic environment with consent, payment initiation, recipient checks and recorded outcomes. It may take a moment to start. This simulator does not contact it.

Explore payments in the ZILLQ sandbox → · Explore the platform