PlexySDK DOCS

Auto Rescue for Cards

Intelligent retry strategies optimized for card payment failures

Auto Rescue for Cards

Auto Rescue for Cards applies specialized recovery strategies for failed card payments. By analyzing decline codes and issuer behavior, Plexy determines the optimal retry timing and approach to maximize recovery rates.

Card Decline Categories

Card declines fall into three categories, each with different recovery strategies:

Soft Declines

Temporary issues that often resolve with time or after card updates.

Decline CodeDescriptionRecovery Strategy
insufficient_fundsCard has insufficient balanceRetry after typical payday (1-3 days)
exceeds_limitOver daily/monthly spending limitRetry after limit reset (1-7 days)
try_again_laterIssuer requests retryRetry in 24-48 hours
do_not_honorGeneric soft declineRetry with Account Updater check
card_velocity_exceededToo many transactionsRetry after 24-72 hours
processing_errorTemporary processing issueRetry in 1-4 hours

Technical Errors

Infrastructure issues requiring immediate retry.

Error CodeDescriptionRecovery Strategy
network_timeoutConnection timed outImmediate retry (3x)
gateway_errorPayment gateway issueImmediate retry
issuer_unavailableIssuer system downRetry every 15-30 minutes
system_errorPlexy system issueAutomatic failover

Hard Declines

Permanent issues that should not be retried.

Decline CodeDescriptionAction
stolen_cardCard reported stolenStop, deactivate payment method
lost_cardCard reported lostStop, deactivate payment method
fraudulentSuspected fraudStop, flag for review
pickup_cardIssuer requests card retrievalStop, deactivate payment method
invalid_accountAccount doesn't existStop, contact customer
expired_cardCard has expiredCheck Account Updater, then stop if no update
restricted_cardCard is restrictedStop, contact customer

Never retry hard declines. Doing so can damage your relationship with issuers, increase your fraud rate, and may violate card network rules.

Retry Schedules

Default ML-Optimized Schedule

Plexy's machine learning model optimizes retry timing based on:

  • Historical recovery patterns
  • Decline code analysis
  • Issuer-specific behavior
  • Day of week and time of month patterns

Typical ML-optimized schedule for insufficient_funds:

RetryTimingRationale
1Day 1-2Quick follow-up
2Day 3-5After initial payday window
3Day 7-10Mid-month window
4Day 14-15Second payday window

Custom Schedule Configuration

Override the default schedule for specific needs:

curl -X POST https://api.plexypay.com/v2/payments \
  -H "x-api-key: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 9900,
    "currency": "USD",
    "customer": "cus_abc123",
    "payment_method": "pm_card_visa_abc123",
    "off_session": true,
    "auto_rescue": {
      "enabled": true,
      "retry_schedule": "custom",
      "custom_schedule_days": [1, 3, 7, 14],
      "max_retries": 4,
      "retry_window_days": 14
    }
  }'
const payment = await plexy.payments.create({
  amount: 9900,
  currency: 'USD',
  customer: 'cus_abc123',
  payment_method: 'pm_card_visa_abc123',
  off_session: true,
  auto_rescue: {
    enabled: true,
    retry_schedule: 'custom',
    custom_schedule_days: [1, 3, 7, 14],
    max_retries: 4,
    retry_window_days: 14,
  },
});
payment = plexy.payments.create(
    amount=9900,
    currency='USD',
    customer='cus_abc123',
    payment_method='pm_card_visa_abc123',
    off_session=True,
    auto_rescue={
        'enabled': True,
        'retry_schedule': 'custom',
        'custom_schedule_days': [1, 3, 7, 14],
        'max_retries': 4,
        'retry_window_days': 14,
    },
)

Decline-Specific Schedules

Configure different schedules based on decline type:

const payment = await plexy.payments.create({
  amount: 9900,
  currency: 'USD',
  customer: 'cus_abc123',
  payment_method: 'pm_card_visa_abc123',
  off_session: true,
  auto_rescue: {
    enabled: true,
    decline_strategies: {
      insufficient_funds: {
        schedule_days: [1, 3, 7, 15], // Align with paydays
        max_retries: 4,
      },
      try_again_later: {
        schedule_hours: [4, 12, 24], // Shorter intervals
        max_retries: 3,
      },
      do_not_honor: {
        schedule_days: [1, 3], // Limited retries
        max_retries: 2,
        check_account_updater: true, // Always check for updates
      },
    },
  },
});

Integration with Account Updater

Auto Rescue automatically checks Account Updater before each retry attempt:

Response with Account Updater

{
  "id": "pay_xyz789",
  "status": "succeeded",
  "auto_rescue": {
    "status": "recovered",
    "attempts_made": 2,
    "recovered_at": "2026-03-27T10:30:00Z"
  },
  "rescue_history": [
    {
      "attempt": 1,
      "attempted_at": "2026-03-25T10:30:00Z",
      "result": "failed",
      "failure_code": "expired_card",
      "account_updater_checked": true,
      "card_was_updated": false
    },
    {
      "attempt": 2,
      "attempted_at": "2026-03-27T10:30:00Z",
      "result": "succeeded",
      "account_updater_checked": true,
      "card_was_updated": true,
      "update_type": "new_expiry"
    }
  ]
}

Network Token Priority

When a card has an active network token, Auto Rescue uses it for retries:

ScenarioBehavior
Network token activeUse network token for all retries
Network token updatedUse updated token credentials
Network token inactiveFall back to stored PAN
{
  "rescue_history": [
    {
      "attempt": 2,
      "result": "succeeded",
      "network_token_used": true,
      "network_token_status": "active"
    }
  ]
}

Webhook Events

payment.rescue_retry (Cards)

{
  "id": "evt_abc123",
  "type": "payment.rescue_retry",
  "created_at": "2026-03-26T10:30:00Z",
  "data": {
    "payment": "pay_xyz789",
    "customer": "cus_abc123",
    "payment_method": "pm_card_visa_abc123",
    "retry_number": 1,
    "previous_decline_code": "insufficient_funds",
    "account_updater_checked": true,
    "card_was_updated": false,
    "network_token_used": true,
    "retry_strategy": {
      "decline_category": "soft_decline",
      "timing_reason": "payday_alignment"
    }
  }
}

payment.rescue_succeeded (Cards)

{
  "id": "evt_def456",
  "type": "payment.rescue_succeeded",
  "created_at": "2026-03-28T14:15:00Z",
  "data": {
    "payment": "pay_xyz789",
    "customer": "cus_abc123",
    "amount": 9900,
    "currency": "USD",
    "retry_number": 2,
    "total_attempts": 3,
    "days_to_recover": 3,
    "recovery_factors": {
      "card_was_updated": true,
      "update_type": "new_expiry",
      "network_token_used": true
    }
  }
}

Handling Specific Decline Codes

Insufficient Funds

The most common soft decline, often recovering after payday.

// Configure payday-optimized retries
const payment = await plexy.payments.create({
  amount: 9900,
  currency: 'USD',
  customer: 'cus_abc123',
  payment_method: 'pm_card_visa_abc123',
  off_session: true,
  auto_rescue: {
    enabled: true,
    decline_strategies: {
      insufficient_funds: {
        // Retry around typical paydays (1st, 15th, Fridays)
        schedule_days: [1, 3, 7, 15, 16],
        max_retries: 5,
        notify_customer_after_attempt: 2, // Email after 2nd failure
      },
    },
  },
});

Expired Card

First check Account Updater, then contact customer if no update found.

app.post('/webhooks/plexy', async (req, res) => {
  const event = verifyWebhook(req);

  if (event.type === 'payment.rescue_retry') {
    const { previous_decline_code, card_was_updated } = event.data;

    if (previous_decline_code === 'expired_card' && !card_was_updated) {
      // No update found for expired card - contact customer
      await sendEmail(event.data.customer, 'card_expired_update_needed', {
        update_url: 'https://yoursite.com/update-payment',
      });
    }
  }

  res.status(200).send('OK');
});

Do Not Honor

A catch-all decline that may indicate various issues.

// Limited retries for "do not honor" - may be semi-hard decline
const payment = await plexy.payments.create({
  amount: 9900,
  currency: 'USD',
  customer: 'cus_abc123',
  payment_method: 'pm_card_visa_abc123',
  off_session: true,
  auto_rescue: {
    enabled: true,
    decline_strategies: {
      do_not_honor: {
        schedule_days: [1, 3],
        max_retries: 2,
        check_account_updater: true, // May be outdated card
        try_alternate_payment_method: true, // Try backup if available
      },
    },
  },
});

Card Brand-Specific Behavior

Different card networks have unique characteristics:

NetworkNotes
VisaMost predictable retry behavior
MastercardStrong Account Updater support
American ExpressMay require shorter retry windows
DiscoverLimited Account Updater coverage

Configure by Card Brand

const payment = await plexy.payments.create({
  amount: 9900,
  currency: 'USD',
  customer: 'cus_abc123',
  payment_method: 'pm_card_visa_abc123',
  off_session: true,
  auto_rescue: {
    enabled: true,
    card_brand_strategies: {
      visa: {
        max_retries: 4,
        schedule_days: [1, 3, 7, 14],
      },
      mastercard: {
        max_retries: 4,
        schedule_days: [1, 3, 7, 14],
      },
      amex: {
        max_retries: 3,
        schedule_days: [1, 3, 7], // Shorter window for Amex
      },
    },
  },
});

Best Practices

Monitor by Decline Code

Track recovery rates by decline code to optimize your strategy:

// Fetch Auto Rescue analytics
const analytics = await plexy.autoRescue.getAnalytics({
  start_date: '2026-03-01',
  end_date: '2026-03-31',
  group_by: 'decline_code',
});

// Example response
// {
//   "insufficient_funds": { "attempts": 1234, "recovered": 456, "rate": 0.37 },
//   "do_not_honor": { "attempts": 567, "recovered": 89, "rate": 0.16 },
//   "expired_card": { "attempts": 234, "recovered": 167, "rate": 0.71 }
// }

Combine with Dunning

Coordinate Auto Rescue with customer communications:

Retry AttemptCustomer Communication
Initial failureOptional: "Payment failed, we'll retry"
After 2nd failure"Payment still failing, please check card"
After 3rd failure"Urgent: Update payment method"
Final failure"Service will be suspended"

Avoid Over-Retrying

Too many retries can:

  • Annoy customers
  • Damage issuer relationships
  • Increase fraud flags

Recommended limits:

Payment TypeMax RetriesWindow
Subscription (< $50)414 days
Subscription (> $50)310 days
One-time purchase27 days

Next Steps

On this page