Auto-rescue

Automatically recover failed payments before the customer sees a decline.

View as MarkdownInstall skills

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 typeExample codesRetried?
Soft decline — insufficient fundsinsufficient_fundsYes
Soft decline — issuer unavailableissuer_unavailableYes
Soft decline — temporary refusaldo_not_honor_retryYes
Network timeoutYes
Acquirer routing failureYes, via alternate acquirer
Hard decline — stolen cardstolen_cardNo
Hard decline — fraud signalfraudNo
Hard decline — card blockeddo_not_honorNo
Hard decline — invalid cardinvalid_accountNo

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 result

If 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:

FieldTypeDescription
attemptNumberintegerWhich attempt this represents (2 for the first retry, 3 for the second, and so on).
previousDeclineCodestringThe decline code returned by the preceding attempt.
newStatusstringThe payment status immediately after this attempt: completed, pending, or failed.
paymentobjectThe 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, and invalid_account are 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

Was this page helpful?
Edit on GitHub

Last updated on

On this page