Auto-rescue
Automatically recover failed payments before the customer sees a decline.
When a payment hits a soft decline or a routing failure, VINR does not immediately surface that failure to the customer. Instead, it enters an auto-rescue cycle — retrying or rerouting the charge silently within the same checkout session. Only if every recovery attempt is exhausted does the customer see a result. The feature is on by default and requires no integration work beyond what you already do to create a payment.
What auto-rescue handlesAsk
Auto-rescue acts on failures that have a meaningful chance of succeeding on a second attempt. It never retries hard declines, where the issuer has given a definitive refusal.
| Failure type | Example codes | Retried? |
|---|---|---|
| Soft decline — insufficient funds | insufficient_funds | Yes |
| Soft decline — issuer unavailable | issuer_unavailable | Yes |
| Soft decline — temporary refusal | do_not_honor_retry | Yes |
| Network timeout | — | Yes |
| Acquirer routing failure | — | Yes, via alternate acquirer |
| Hard decline — stolen card | stolen_card | No |
| Hard decline — fraud signal | fraud | No |
| Hard decline — card blocked | do_not_honor | No |
| Hard decline — invalid card | invalid_account | No |
Hard declines are never retried. Attempting to authorize a card the issuer has flagged as stolen or fraudulent wastes your authorization budget and can trigger network penalties. Auto-rescue only acts on codes that carry an implicit "try again" signal.
How it worksAsk
Within a single checkout session, VINR may make up to three authorization attempts (configurable). Attempts use exponential back-off with a small jitter to avoid hammering an issuer that is experiencing load:
Attempt 1 → failure → wait ~1 s → Attempt 2 → failure → wait ~4 s → Attempt 3 → final resultIf rerouteOnFailure is enabled (the default), attempts after the first may be routed to an alternate acquirer. VINR selects the alternate based on historical approval rate data for the card BIN, currency, and amount range. From the customer's perspective, the checkout page enters a brief "processing" state for the duration of the rescue cycle. Your webhook receives the final outcome — succeeded or failed — once the cycle is complete.
Auto-rescue operates entirely server-side. You do not need to poll or handle intermediate events. The payment.completed or payment.failed webhook fires exactly once, after the final attempt.
Enable and configureAsk
Auto-rescue is enabled by default on every payment. To adjust its behaviour, pass an autoRescue object to payments.create.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
const payment = await vinr.payments.create({
amount: 4900,
currency: 'EUR',
customer: 'cust_9aQ2',
returnUrl: 'https://yoursite.com/payment/complete',
autoRescue: {
enabled: true,
maxAttempts: 3,
rerouteOnFailure: true,
},
});
// payment.id → "pay_3Nf8x2a..."
// payment.status → "pending"To disable auto-rescue entirely for a specific payment — for example when you want to handle retry logic yourself — set enabled: false.
const payment = await vinr.payments.create({
amount: 4900,
currency: 'EUR',
customer: 'cust_9aQ2',
returnUrl: 'https://yoursite.com/payment/complete',
autoRescue: { enabled: false },
});Monitoring rescue attemptsAsk
When auto-rescue makes one or more intermediate attempts before reaching a final result, VINR emits a payment.rescue_attempted event for each retry. Subscribe to it to track recovery rates and identify patterns in your decline codes.
const event = vinr.webhooks.verify(payload, signature);
if (event.type === 'payment.rescue_attempted') {
const { attemptNumber, previousDeclineCode, newStatus } = event.data.object;
console.log(`Attempt ${attemptNumber} after decline: ${previousDeclineCode}`);
console.log(`Status after this attempt: ${newStatus}`);
}The event payload fields:
| Field | Type | Description |
|---|---|---|
attemptNumber | integer | Which attempt this represents (2 for the first retry, 3 for the second, and so on). |
previousDeclineCode | string | The decline code returned by the preceding attempt. |
newStatus | string | The payment status immediately after this attempt: completed, pending, or failed. |
payment | object | The full payment object at the time of the event. |
payment.rescue_attempted is informational. You do not need to take any action in response to it. Wait for payment.completed or payment.failed before fulfilling or abandoning the order.
When auto-rescue does not helpAsk
Auto-rescue only applies to on-session payments where the customer is present in the checkout flow. It does not cover:
- Hard declines. Codes such as
stolen_card,fraud,do_not_honor, andinvalid_accountare definitive. VINR surfaces these immediately without retrying. - Off-session subscription charges. When VINR bills a stored payment method without the customer present, there is no checkout session to extend. Failed off-session charges are handled through dunning — a separate retry-and-notify process tied to your subscription lifecycle. See Recurring payments for how to handle those failures and how Billing subscriptions can own the dunning schedule for you.
- Authentication failures. If a payment fails because 3DS authentication was not completed, retrying the authorization without re-challenging the customer will not help. Redirect the customer to complete authentication instead.
Prop
Type
Increasing maxAttempts beyond 3 extends the time the customer spends on the "processing" screen. Evaluate the tradeoff between recovery rate and perceived latency for your checkout flow before raising the ceiling.
AdvancedAsk
Next stepsAsk
Recurring payments
Manage off-session charges, mandates, and dunning for subscriptions.
Fraud prevention
Risk scoring and rules that run before auto-rescue.
Declines and failures
Decode decline codes and decide how to respond.
Last updated on