The short answer: do not make “payment failed” point directly to “retry.” First determine whether the previous attempt has a known outcome. Then follow the current provider or network advice into one of three classes: stop, request customer action, or make a bounded retry. Only after that should billing and product-access policies change.
That order prevents two opposite failures: charging twice after a timeout that hid a success, and abandoning a recoverable renewal because authentication, corrected data, or a later attempt was required.
Start with outcome certainty, not a decline label
An API timeout is not the same as a declined authorization. The client may lose the response after the processor accepted the request. A gateway may return an indeterminate error while its event arrives later. If the scheduler immediately creates a new charge, the system can turn uncertainty into a duplicate.
For every attempt, retain the invoice ID, unique attempt ID, idempotency key, processor route, amount, request time, provider reference, normalized result, raw code, advice, and event time.
When the outcome is unknown, query the provider using the stable identifier and consume the authoritative event stream. If a success exists, continue from that object. If the provider confirms that no charge was created or that it failed, classification can begin. “We did not receive HTTP 200” is not enough evidence for a second attempt.
Use advice before inventing “soft” and “hard” buckets
Teams often maintain a local list of soft and hard declines. That can be useful, but it should not outrank fresher provider advice.
Stripe's current decline documentation illustrates the stronger contract. Its outcome can include an advice_code such as do_not_try_again, try_again_later, or confirm_card_data. The decline code explains the observed category; the advice says what should happen next. Visa's public response-code reference likewise distinguishes conditions such as insufficient funds, expired card, additional authentication required, duplicate transaction, system malfunction, and stop-payment responses.
Normalize provider output into three next-action classes while preserving the raw source:
| Action class | Typical signal | System behavior |
|---|---|---|
| Stop | do not retry, stop payment, lost/stolen, ineligible for resubmission | disable automatic attempts for this instruction; offer a safe allowed alternative |
| Customer action | authentication required, incorrect data, expired or unusable method, contact issuer | pause automation; send the customer to the exact corrective step |
| Bounded retry | explicit try-later advice or confirmed transient processing failure | schedule only within provider, network, and merchant limits |
A generic decline is not positive proof that retrying is allowed. Route it through the provider's documented handling or manual policy rather than guessing from its name.
Stop paths must disable the scheduler
A terminal branch needs more than a red box in a dashboard. It must prevent another worker, delayed queue message, or nightly dunning job from submitting the same instruction.
The stop transition should record whether it applies only to this attempt, this invoice's automatic collection, the stored method, or future recurring instructions.
Visa publishes distinct stop-payment-related response codes, which is a useful reminder that “do not retry this authorization” and “stop future payments” are not interchangeable claims. Implement the exact scope supplied by the provider or network. Do not broaden or narrow it based on a generic local label.
Customer communication must also be safe. Fraud-related details may be intentionally vague; offer another permitted method without exposing internal risk logic.
Customer-action paths are not timed retries
Authentication required, incorrect card data, an expired card, or an issuer-contact instruction all need a person to change the state. Running the same request tomorrow does not perform 3D Secure, correct an expiry date, or confirm identity with the issuing bank.
Make the flow explicit:
attempt requires action
→ set collection state to customer_action_required
→ create one scoped portal or authentication task
→ notify through approved channels
→ wait for a new method or completed action event
→ create a new attempt with a new identity
Retry paths need a budget and a deadline
An explicit retryable signal still does not mean “repeat until approved.” Stripe warns that card networks limit reattempts and notes that excessive retries can look fraudulent and raise declines. The correct quota is not a number copied from a blog post; it is the current limit and advice applicable to the merchant's processor, network, region, and transaction type.
Represent the retry budget as data:
| Field | Purpose |
|---|---|
| first failure time | starts the recovery window |
| retry count by instruction and method | enforces provider or network limits |
| next eligible time | prevents immediate loops |
| current advice source and version | explains why retry remains allowed |
| recovery deadline | hands off to invoice or access policy |
| route history | prevents accidental cycling across processors |
The retry branch should end when any limit is reached, the subscription changes, the invoice is paid elsewhere, the customer revokes the method, or fresher advice says stop.
Rerouting is not a way around an issuer decision
Multi-processor orchestration can help when the failure belongs to a processor path, regional coverage, or a confirmed transient route condition. It must not be drawn as “Processor A declined → keep trying processors until one says yes.”
Before a reroute, test:
- Is the previous outcome definitively unsuccessful?
- Does current advice permit another attempt?
- Can the token or payment reference be used on the alternate route under the merchant's agreements and consent model?
- Will the new route preserve recurring-payment indicators, authentication evidence, amount, currency, and merchant context?
- Is the reroute inside the same retry budget and audit history?
Clink's Smart Routing product is one implementation surface for dynamic routing, backup processors, automatic retries, and configurable priorities. Its product page establishes those offered capabilities; it does not replace the network, acquirer, issuer, or merchant rules that determine whether a specific payment may be retried. There is no claimed native ChatDiagram–Clink integration here.
Keep payment recovery separate from product access
A payment attempt can fail while the subscription remains in a grace period. It can later succeed after the customer updates a method. Conversely, a successful authorization does not settle every risk, refund, entitlement, or contract question.
Every terminal flowchart path should update four records separately:
- attempt history: the immutable result and advice;
- invoice collection: paid, open, customer action required, or collection ended;
- subscription: current agreement and any future change;
- entitlement: full, grace, limited, or revoked under a versioned merchant policy.
Do not let the retry worker revoke access directly. It should emit a collection fact. The entitlement policy decides the product consequence.
A route test set catches the dangerous gaps
Before release, trace at least these cases through the diagram and the implementation:
- Timeout, but a later event confirms success.
- Timeout, provider lookup confirms no created payment.
- Explicit do-not-retry advice.
- Authentication required while the customer is off-session.
- Expired method, then a successful customer update.
- Explicit try-later advice inside the retry budget.
- Retry budget exhausted without success.
- A late success event after the invoice was paid by another route.
- Subscription canceled while a delayed retry job is queued.
- Stop-payment instruction arriving after an earlier recoverable decline.
For each case, assert the number of money-movement attempts, the final invoice state, the subscription state, the access state, and the message sent. A diagram that shows only the happy recovery path is not ready to control a billing worker.
You can adapt the review model in ChatDiagram's flowchart maker, then replace every generic branch with the exact normalized codes and policies used by your stack. Keep a legend that points from each branch to its provider documentation and test fixture.
Where this flowchart stops
This article does not grant a right to resubmit a payment, choose a retry count, interpret a card-network rule, or define customer notice. It does not cover bank-debit return windows, local payment methods, fraud review, chargebacks, or jurisdiction-specific collection law.
Its claim is narrower: a safe retry system makes uncertainty visible, follows explicit advice, limits automation, and preserves payment, billing, subscription, and access as separate histories. That structure is testable even when the exact rules vary.
Cite this article
Use ChatDiagram for the review flow and cite the applicable network, acquirer, or PSP documentation for an exact code or retry rule. Preserve the outcome-reconciliation gate and the three action classes if you reuse the diagram; removing either turns a controlled recovery process back into a blind loop.