Blog
A red glass barrier separates a bank card and receipt beside a mechanical switch.

August 26, 20265 min readАдминистратор

Retry or stop? Keeping a decline from becoming a duplicate charge

Timeouts, declines and permitted retries need different actions. Use two counters, recheck the backlog and measure recovery cost.

The most dangerous button after a timeout is Try again when nobody knows what happened to the original payment. The customer, server and background worker can all trigger it almost simultaneously. A retry policy must establish the first outcome, check the permitted next action and only then count a recovered sale.

First establish whether the payment was declined

Separate invalid requests, definite negative payment outcomes, and requests whose responses were lost. That last group has an unknown outcome. Creating a new payment immediately can cause a duplicate charge. Check the original operation through the available status mechanism and process its notifications first. Customer messaging should acknowledge the uncertainty: “We’re checking your payment. Please wait for the result.”

Stripe explains that a network failure does not establish whether an operation ran. Permitted retries of the same request use the same idempotency key and parameters within the applicable window; indeterminate outcomes need reconciliation. Exact behavior depends on the API version. Source: Stripe, Advanced error handling.

Soft and hard labels need an underlying reason

Separating temporary from persistent declines can guide the next action. However, “soft decline” and “hard decline” are not substitutes for the method’s documentation. A temporary condition may clear later. Another response may require corrected information, customer participation, or an end to further attempts. An unknown reason should not automatically be treated as temporary.

Stripe’s code reference maps authentication requirements to customer authentication, an expired card to another card, and some general declines to contacting the issuer. Different codes need different actions; retrying every decline is not a valid universal rule. Source: Stripe, Decline codes.

An illustrative, tightly bounded policy

Imagine a team handling one-time card purchases. It permits at most one additional automatic attempt, only for a temporary reason that the provider explicitly allows to be retried, and only after the advised interval. If that attempt fails, automation stops and the customer receives the appropriate next step. “One” is an illustrative internal limit, not a card-network rule.

The policy must also obey any stricter provider or network restriction. An internal limit cannot authorize a prohibited retry. Waiting does not satisfy a requirement for authentication. If the customer cancels or the authority to charge is revoked, the background process must not keep pursuing the previous flow.

Consider 100 unsuccessful orders: 60 have unknown outcomes, 25 have definite declines requiring no automatic repeat, and 15 are eligible for a provider-permitted retry. Sending 100 new payments would be wrong. Investigate the 60 unresolved operations, present the appropriate customer action for the 25 declines, and evaluate only the remaining group for a bounded retry. This separates technical recovery from a new authorization attempt.

Use two counters rather than one retry limit

Separate technical request delivery from a new authorisation attempt. Keep two counters: how many times the same action was transmitted to obtain a reliable outcome, and how many independent payment attempts belong to the order. Otherwise, three network transmissions can be mistaken for three new payments, or new attempts can disappear behind the generic label Retry.

For each permitted next action, retain its basis: specific response, applied rule, time and checked order state. This makes the decision explainable after an incident. “Automatically allowed” does not show why the permission applied to this particular operation.

When connectivity returns, verify that a backlog does not execute actions that have become unnecessary. Recheck order state and current authority before each delayed attempt. If the customer paid using another method during the outage, the old job should complete without initiating another charge.

Put duplicate prevention around the entire workflow

  • Persist order state, operation reference, attempt count, and next permitted action time.
  • Coordinate interface, server, queue, and provider retries under one process owner.
  • Before another attempt, verify that the order is unpaid, uncancelled, and not still processing.
  • Do not generate a fresh key merely to escape an unresolved original request.
  • Stop automation when a prohibition, retry limit, or customer-action requirement applies.

Transport success also needs a business-result check. Adyen documents that HTTP 200 can accompany an authorization refusal, with payment response fields describing the outcome. HTTP status alone is therefore insufficient evidence that an order was paid. Source: Adyen, Refusal reasons.

Price recovery against the eligible group

Return to the fifteen orders eligible for a retry in the hypothetical example. Suppose one additional attempt per order recovers six. Success for that step is 6 / 15 = 40%, while additional attempts per recovered order are 15 / 6 = 2.5. These describe the eligible group, not overall recovery across the hundred original cases.

Check completion quality alongside those numbers. Were there duplicate charges, cancelled orders, duplicate fulfilments or inaccurate customer messages? An order that technically succeeded but then needed a duplicate-payment refund should not be presented as an unqualified benefit of the policy.

The operating procedure needs an owned stop control: who can halt automatic retries, which signal triggers it and how the remaining queue is handled. Define resumption separately, including a review of accumulated states. Simply enabling the old queue again can revive requests whose meaning has changed during the incident. Keep the stop reason and the resumption check with the incident record so later reviewers can distinguish deliberate recovery from uncontrolled replay.

What to tell the customer when automation stops

Support teams also need clear instructions that do not reveal internal fraud signals. Offer actions appropriate to the actual reason: complete authentication, correct information through a secure form, contact the issuer, or use a permitted payment method. These are card-payment examples. Bank transfers and other methods require their own status models and recovery procedures.

Review the policy whenever provider guidance or integration behavior changes. The objective is a correctly completed, authorized payment with a traceable history. Security checks and participant restrictions must remain intact throughout recovery.

Sources

  1. 1.docs.stripe.com/error-low-level
  2. 2.docs.stripe.com/declines/codes
  3. 3.docs.adyen.com/development-resources/refusal-reasons

Comments · 0

No comments yet — be the first.

Log in · log in to leave a comment.