Skip to main content
This guide shows the recommended flow: your checkout stays exactly as it is, and Revtain handles recovery when payments fail.
Your checkout doesn’t change. Customers continue to pay with whatever you already support. Revtain operates entirely behind the scenes — no UI changes, nothing customer-facing.

How It Works

1

Customer pays through your existing checkout

Stripe, Chargebee, custom — anything.
2

Payment succeeds → log it (optional)

Call /pulse so Revtain can calculate Lift accurately.
3

Payment fails → hand off to Revtain

Pass the gateway token, amount, and decline code.
4

Revtain runs the engine

Intelligent retries with prediction-driven timing directly against the gateway that issued the original token.
5

You receive a webhook with the result

recovery.success, recovery.failed, or recovery.blocked.

Backend: Charge, Then Recover

app.post('/your-backend/charge', async (req, res) => {
  const { paymentMethodId, amount, stripeCustomerId } = req.body;

  let declineCode;

  // 1. Try charging through YOUR primary gateway using YOUR token
  //    (Your normal checkout — Revtain not involved yet)
  try {
    const charge = await stripe.paymentIntents.create({
      amount,
      currency: 'usd',
      customer: stripeCustomerId,
      payment_method: 'pm_xxx',
      confirm: true
    });

    // Log the organic success so Revtain can calculate Lift
    await fetch(`${REVTAIN_BASE_URL}/api/recovery/pulse`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-KEY': process.env.REVTAIN_API_KEY
      },
      body: JSON.stringify({ amount, currency: 'USD', transactionId: charge.id })
    });

    return res.json({ success: true, chargeId: charge.id });
  } catch (stripeError) {
    declineCode = stripeError.decline_code;
  }

  // 2. Primary failed — hand off to Revtain
  const recovery = await fetch(`${REVTAIN_BASE_URL}/api/recovery/execute`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-KEY': process.env.REVTAIN_API_KEY
    },
    body: JSON.stringify({
      paymentMethodToken: paymentMethodId,
      amount,
      currency: 'USD',
      originalDeclineCode: declineCode,
      cardOrigin: 'US',
      idempotencyKey: `order_${orderId}_recovery`,
      // Set when the failed charge came from Apple Pay / Google Pay / PayPal.
      // Defaults to 'card' if omitted. Wallet payments get a higher predicted
      // recovery score, so passing this correctly meaningfully lifts results.
      paymentMethodType: payment.paymentMethodType || 'card',
      // Optional: pass any alternative payment tokens you hold for this
      // customer (e.g. a backup card-on-file when the primary is a wallet).
      // Revtain tries each in order if the primary's cascade exhausts on a
      // recoverable decline. Up to 5 supported. No orchestration code needed.
      fallbackPaymentMethodTokens: payment.fallbackTokens || []
    })
  });

  const result = await recovery.json();

  if (recovery.status === 200 && result.success) {
    return res.json({ success: true, recovered: true, transactionId: result.transactionId });
  } else if (recovery.status === 202) {
    return res.json({ success: false, queued: true, message: result.message });
  } else if (recovery.status === 403) {
    return res.status(403).json({ success: false, blocked: true, error: result.error });
  } else if (recovery.status === 409) {
    return res.json({ success: false, duplicate: true, existing: result.existingTransactionId });
  }

  return res.json({ success: false, error: result.error || result.message });
});

Custom / In-House Billing

For in-house billing without a webhook event, call Revtain directly from your payment failure handler:
async function handlePaymentFailure(payment) {
  const recovery = await fetch('https://api.revtain.com/api/recovery/execute', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-KEY': process.env.REVTAIN_API_KEY
    },
    body: JSON.stringify({
      paymentMethodToken: payment.paymentToken,
      amount: payment.amountCents,
      currency: payment.currency || 'USD',
      originalDeclineCode: payment.declineCode || 'unknown',
      idempotencyKey: `custom_${payment.id}_recovery`
    })
  });
  return recovery.json();
}
The only requirement is that you have the customer’s payment token from your gateway. Everything else is the same regardless of billing platform.
Apple Pay / Google Pay / PayPal customers. Any gateway-native token works — including the pm_xxx tokens Stripe issues for Apple Pay and Google Pay charges. Pass the wallet identifier in paymentMethodType (apple_pay, google_pay, paypal, or venmo) so the recovery engine applies the right strategy. Recovery rates on wallet payments are materially higher when this field is set correctly — wallet tokens ride network tokens with built-in cryptograms, which the predictor weights accordingly.
Customers with more than one stored payment method. Pass any alternative tokens you hold in fallbackPaymentMethodTokens. If the primary token’s gateway cascade exhausts on a recoverable decline, Revtain tries each fallback in order automatically — no orchestration code on your side. Common use: wallet primary + backup card-on-file. Up to 5 fallback tokens supported.

Optional: Pre-Screening Risky Payments

Before charging a payment, you can ask Revtain to score the risk of failure. This is most useful for high-value or first-time-in-a-billing-cycle charges where a wasted attempt can hurt your merchant standing.
curl -X POST https://api.revtain.com/api/predict/risk \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: rev_YOUR_API_KEY" \
  -d '{
    "paymentMethodToken": "pm_1234567890",
    "amount": 5000,
    "currency": "USD"
  }'
Response:
{
  "success": true,
  "prediction": {
    "riskScore": 72.5,
    "recommendation": "delay",
    "reasoning": "Card has 3 prior declines in last 30 days. Amount matches a historically recoverable pattern."
  }
}
recommendationWhat to do
proceedCharge normally
proceed_with_cautionCharge but monitor for failure
delayHold the charge for a Revtain-recommended retry window
blockDo not charge — high chance of decline or chargeback
You can also subscribe to the predict.risk.high webhook to receive automatic alerts for customers whose stored payment method has crossed a risk threshold. See Webhooks → predict.risk.high.
Need help? Contact the Revtain team at support@revtain.com for guidance on integrating with your specific billing platform.