# Retry a payment

Whether a payment that didn't go through is worth sending again, and the request that sends it again without charging the customer twice.

2 questions, 6 outcomes

## What came back from the payment?

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/what-came-back.md

Each of these is retried differently, and some aren't retried at all. Read the resultCode on the response, or the HTTP status when there's no transaction.

**Choose one**

- Nothing. The request timed out or the connection dropped. You don't know whether the payment happened. Leads to: Ask before you resend.
- A failure. The platform couldn't complete the request. The resultCode names a fault, such as TimeoutWaitingForProcessorResponse. Leads to: Send a new payment once the fault clears.
- A decline from the card issuer or the processor. The resultCode is Decline, or another refusal value. Leads to: Which decline reason code did you get?.
- A refusal by the merchant's own rules. A policy rejection, a review decline, or a 403 screening stop. Leads to: Change the request before you send it again.

### Ask before you resend

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/ask-before-you-resend.md

The payment may have gone through. Find out before you send anything that could charge the customer a second time.

**What to build**

Look the payment up by the idempotency key you sent with it. If a transaction comes back, that's your answer. If none does, resend the original request with the same key: the platform runs it once however many times it arrives.

**Worth knowing**

- This only works if every create carries a key. Choose one per logical payment, store it before you send, and keep it for every attempt at that payment.
- Choose your own client timeout, and run the slow-processor scenario in the sandbox so the timeout path is code you've exercised.

**Where to go next**

- [Retry a payment without a double charge](https://devportal.qa.winkpg.io/docs/blueprints/retry-a-payment-safely.md)
- [Look up a transaction by idempotency key](https://devportal.qa.winkpg.io/docs/api/transactionsGetByIdempotencyKey.md)
- [Getting started with the API](https://devportal.qa.winkpg.io/docs/guides/api-getting-started.md)

### Send a new payment once the fault clears

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/send-a-new-payment-once-the-fault-clears.md

Nothing was decided and no funds were held. The payment simply didn't happen.

**What to build**

Don't route a failure through your decline handling. Once the fault has cleared, create the payment again under a new idempotency key. Don't rely on the Retry operation here: it's seldom offered on a failure, so read the transaction's allowedActions list rather than assuming.

**Worth knowing**

- A new attempt needs a new idempotency key. A create that got an answer is replayed under its key for 48 hours, so resending with the old one hands you the same refused transaction.
- A failure arrives as Transaction.Failed, not Transaction.Declined. Subscribe to both if your systems react to refused payments.
- Where the merchant has more than one processor, the platform may already have failed over before you saw the result.

**Where to go next**

- [Understanding declines and rejections](https://devportal.qa.winkpg.io/docs/guides/understanding-declines-and-rejections.md)
- [Processor routing and failover](https://devportal.qa.winkpg.io/docs/guides/processor-routing-and-failover.md)
- [Retry a payment without a double charge](https://devportal.qa.winkpg.io/docs/blueprints/retry-a-payment-safely.md)

### Which decline reason code did you get?

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/which-decline-reason-code.md

Read declineReasonCode on the response. It's the same vocabulary whichever processor handled the payment, and it's the only field to branch on.

**Choose one**

- A funding or limit code. INSUFFICIENT_FUNDS, ACTIVITY_LIMIT_EXCEEDED, or EXCEEDS_APPROVAL_AMOUNT. Leads to: Retry later, spaced by days.
- An availability code. ISSUER_UNAVAILABLE, SYSTEM_MALFUNCTION, or CB_OPEN. Leads to: Retry once the issuer or processor recovers.
- Any other code, or none at all. DO_NOT_HONOR, EXPIRED_CARD, SUSPECTED_FRAUD, and every value not listed above. Leads to: Stop, and ask for another payment method.

#### Retry later, spaced by days

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/retry-later-spaced-by-days.md

The balance or the daily limit resets, so a later attempt with the same card can succeed without the customer doing anything.

**What to build**

Send the Retry operation on the declined transaction, which the card networks permit for these three codes. Space attempts by days rather than minutes, cap the number of attempts, and stop as soon as a retry comes back with a code outside this set.

**Worth knowing**

- An issuer that reports insufficient funds now reports it again a minute from now. Retrying within minutes only adds declines to the card's history.
- Where the customer isn't present for the retry, a fresh charge under a stored-credential consent is the other path, and it's reported as merchant-initiated.

**Where to go next**

- [Understanding declines and rejections](https://devportal.qa.winkpg.io/docs/guides/understanding-declines-and-rejections.md)
- [Run an operation on a transaction](https://devportal.qa.winkpg.io/docs/api/transactionOperationsExecuteOperation.md)
- [Simulate a card decline](https://devportal.qa.winkpg.io/docs/blueprints/simulate-a-card-decline.md)

#### Retry once the issuer or processor recovers

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/retry-once-the-issuer-recovers.md

Something between the platform and the issuer was unavailable. The card itself wasn't refused.

**What to build**

Wait, then create the payment again as a new transaction under a new idempotency key. The Retry operation isn't offered for these codes, because the card networks only permit resubmitting a decline tied to the cardholder's funds or limits.

**Worth knowing**

- A new attempt needs a new idempotency key. A create that got an answer is replayed under its key for 48 hours, so resending with the old one hands you the same refused transaction.
- CB_OPEN means the platform suspended traffic to a processor that was failing and sent nothing. Retry after it recovers, not straight away.
- Back off between attempts. A burst of retries against an issuer that's down only lengthens the queue it's recovering from.

**Where to go next**

- [Understanding declines and rejections](https://devportal.qa.winkpg.io/docs/guides/understanding-declines-and-rejections.md)
- [Retry a payment without a double charge](https://devportal.qa.winkpg.io/docs/blueprints/retry-a-payment-safely.md)
- [Processor routing and failover](https://devportal.qa.winkpg.io/docs/guides/processor-routing-and-failover.md)

#### Stop, and ask for another payment method

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/stop-and-ask-for-another-payment-method.md

Presenting the same card again gets the same answer. Nothing your code can do changes this one.

**What to build**

Don't retry. Tell the customer the payment didn't go through and ask for a different payment method. Record the decline reason code against the order for your support team, and never show the customer the declineReasonDescription text: its wording can change without notice.

**Worth knowing**

- A card the issuer reports as lost or stolen must never be presented again.
- A decline the platform can't classify is treated as terminal on purpose. Stopping is the safe default for a retry decision.
- On a stored payment method, a terminal decline is the moment to ask the customer to update their card rather than to keep charging it.

**Where to go next**

- [Understanding declines and rejections](https://devportal.qa.winkpg.io/docs/guides/understanding-declines-and-rejections.md)
- [Simulate a card decline](https://devportal.qa.winkpg.io/docs/blueprints/simulate-a-card-decline.md)

### Change the request before you send it again

https://devportal.qa.winkpg.io/docs/decide/retry-a-payment/change-the-request-before-sending-it-again.md

A rule the merchant configured refused the payment. The rule is deterministic, so the identical request is refused again.

**What to build**

Don't retry unchanged. For an address or security code rejection, ask the customer to correct what they typed and send a new payment. For a review decline, the reviewer's answer stands, and a new attempt is a new transaction. For a screening stop, the merchant's operator can see which rule fired on the transaction record; nothing changes until they act on it.

**Worth knowing**

- Identical retries in quick succession are exactly the pattern a velocity rule exists to catch, so a retry loop can lock out a legitimate customer.
- CV_REJECTED is the one refusal where the issuer approved and placed a hold before the merchant's address or security code rule refused the payment. The platform releases that hold with an automatic reversal, so confirm the reversal before you tell the customer nothing was held.
- SCREENING_UNAVAILABLE is the exception to all of this: an external screening provider didn't answer, and a later retry can succeed with no change to the request.
- Show the customer the generic result message. The specific rule that refused them isn't something to publish to the person it stopped.

**Where to go next**

- [Understanding declines and rejections](https://devportal.qa.winkpg.io/docs/guides/understanding-declines-and-rejections.md)
- [Handle a CVV mismatch](https://devportal.qa.winkpg.io/docs/blueprints/test-cvv-mismatch-handling.md)
- [Test AVS responses](https://devportal.qa.winkpg.io/docs/blueprints/test-avs-responses.md)

- [Decision guides](https://devportal.qa.winkpg.io/docs/decide.md): every decision guide this instance publishes.

## See also

- [All documentation](https://devportal.qa.winkpg.io/llms.txt): the machine-readable index of every public page on this site.
