Card Expiry Reminders for Stripe SaaS

Send card expiry reminders by checking each customer's card.exp_month and card.exp_year via the Stripe API, then emailing at 30, 14, and 3 days before expiration. Expired cards cause 25-30% of all failed payments. Pre-dunning reminders prevent 55-65% of those failures from ever happening.

The best way to handle a failed payment is to prevent it from happening. Expired credit cards are the #1 cause of failed subscription payments, responsible for 25-30% of all involuntary churn. The card expiry date is predictable. it's right there in the Stripe API. Yet most SaaS companies wait until the payment fails, then scramble to recover it with dunning emails. Pre-dunning card expiry reminders flip this approach: you contact the customer before the failure, while their subscription is still active and there's no urgency or friction. SaaS companies using pre-dunning report a 30-40% reduction in failed payments from expired cards. See the failed payment recovery benchmarks for supporting data. Use our dunning ROI calculator to estimate the impact, and combine pre-dunning with a full dunning setup in Stripe.

Why pre-dunning matters

Dunning (recovering after a failure) has a recovery ceiling. Even with a perfect multi-email sequence, Smart Retries, and in-app banners, you'll recover about 55-65% of failed payments. That means 35-45% are permanently lost. Pre-dunning targets the prevention side: if the customer updates their card before it expires, the payment never fails in the first place. There's nothing to recover.

The conversion rate on pre-dunning emails is also higher than dunning emails. A customer who gets a friendly "Hey, your card expires next month. want to update it?" email converts at 25-35%. A customer who gets a "Your payment failed" email converts at 15-25%. Pre-dunning has better optics (you look proactive instead of chasing payment), less urgency stress, and the customer's card is still technically valid when they click through to update.

Stripe's automatic card updater

Before building pre-dunning, know that Stripe already handles some expired cards automatically. Stripe participates in Visa Account Updater (VAU) and Mastercard Automatic Billing Updater (ABU). These programs let card networks push updated card details to merchants when a bank issues a replacement card.

How it works: when a customer's card expires and the bank issues a replacement (same account, new number/expiry), the card network notifies Stripe. Stripe automatically updates the stored PaymentMethod with the new details. The next charge goes through on the new card without the customer doing anything. This is enabled by default on most Stripe accounts.

Limitations: the card updater doesn't work for all card types, all banks, or all countries. It covers roughly 60-70% of US and EU cards. It also only works when the bank issues a direct replacement. If the customer closes the account or switches banks entirely, the updater has nothing to push. That leaves a significant gap that pre-dunning emails fill.

Method 1: Stripe API polling

The most straightforward approach is to periodically query the Stripe API for customers whose payment method is about to expire. Here's the implementation:

Step 1: List expiring payment methods

// Run this daily via cron job
const now = new Date();
const thirtyDaysFromNow = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
const targetMonth = thirtyDaysFromNow.getMonth() + 1;
const targetYear = thirtyDaysFromNow.getFullYear();

// Get all active subscriptions
const subscriptions = await stripe.subscriptions.list({
  status: 'active',
  limit: 100,
  expand: ['data.default_payment_method'],
});

// Filter for expiring cards
const expiring = subscriptions.data.filter(sub => {
  const pm = sub.default_payment_method;
  if (!pm || pm.type !== 'card') return false;
  return pm.card.exp_month === targetMonth
      && pm.card.exp_year === targetYear;
});

// Send reminder emails to expiring customers
for (const sub of expiring) {
  await sendCardExpiryReminder(sub.customer, sub.default_payment_method);
}

Step 2: Build the reminder sequence

Send three emails at escalating intervals:

  • 30 days before expiry: "Heads up: your card ending in {last4} expires next month. Update it now to avoid any interruption."
  • 14 days before expiry: "Reminder: your card expires in 2 weeks. Update it in 30 seconds so your {product} access isn't interrupted."
  • 3 days before expiry: "Your card expires in 3 days. This is the last reminder before your next payment attempt."

Include a direct link to update the card. Use Stripe's Billing Portal for the update page:

const session = await stripe.billingPortal.sessions.create({
  customer: customerId,
  return_url: 'https://yourapp.com/settings',
  flow_data: {
    type: 'payment_method_update',
  },
});
// session.url = card update link for the email

Step 3: Track and deduplicate

Store which reminders you've sent in your database to avoid sending duplicates. Track open rates and card update conversions. When a customer updates their card, stop the reminder sequence (listen for payment_method.attached or customer.updated events).

Build time: 8-15 hours for the cron job, email templates, deduplication logic, and tracking. You'll also need to handle pagination for the Stripe API if you have more than 100 active subscriptions.

Method 2: Stripe webhook listener

Instead of polling the API daily, you can listen for the customer.source.expiring webhook event. Stripe fires this event approximately 30 days before a card's expiration date.

// Webhook handler for card expiry
app.post('/webhooks/stripe', async (req, res) => {
  const event = stripe.webhooks.constructEvent(
    req.body, sig, endpointSecret
  );

  if (event.type === 'customer.source.expiring') {
    const source = event.data.object;
    const customerId = source.customer;

    // Start your 3-email pre-dunning sequence
    await startCardExpirySequence(customerId, {
      last4: source.last4,
      expMonth: source.exp_month,
      expYear: source.exp_year,
    });
  }

  res.json({ received: true });
});

Important note: the customer.source.expiring event fires for legacy Source objects. If your customers are using PaymentMethods (the newer API), you may not receive this event. In that case, use the API polling method (Method 1) or check the payment_method.automatically_updated event to identify cards that were updated and therefore don't need reminders.

Advantage over polling: no cron job needed. Stripe tells you when a card is expiring, and you react. Less infrastructure, fewer moving parts.
Disadvantage: you only get a ~30-day heads up, and it doesn't work for all payment method types. The polling method gives you more control over timing.

Method 3: Tool-assisted pre-dunning

SaveMRR's Pre-Dunning Alerts engine handles card expiry monitoring automatically. It connects to your Stripe account, continuously monitors all active payment methods for upcoming expiry dates, and sends a branded 3-email reminder sequence at 30, 14, and 3 days before expiry. It also tracks which customers updated their card and stops the sequence automatically.

The setup is a Stripe API key paste. No cron jobs, no webhook endpoints, no email templates, no deduplication logic. SaveMRR handles the full lifecycle and reports the results in your dashboard: how many cards were expiring, how many customers updated, and how many failures were prevented.

Pre-dunning email best practices

  • Keep subject lines simple. "Your card ending in 4242 expires next month" outperforms clever marketing copy
  • Include the card's last 4 digits. helps the customer identify which card you're talking about
  • One CTA: update card. don't distract with feature announcements or promotions. One button, one action.
  • Make the update link prominent. large button, above the fold, in a contrasting color
  • Use transactional tone. pre-dunning emails should read like account notifications, not marketing emails. This also improves deliverability.
  • Don't send if card was already updated. check for payment_method.automatically_updated events before sending. If Stripe's card updater already refreshed the card, the reminder is unnecessary.
  • Mention what's at stake. "Your {product} access won't be interrupted if you update before {date}" is more effective than generic "please update your card"

Expected impact

Based on data from SaaS companies using pre-dunning:

  • 30-40% reduction in failed payments caused by expired cards
  • 25-35% click-through rate on pre-dunning emails (vs 15-25% on post-failure dunning emails)
  • 8-12% improvement in overall payment success rate when combined with Smart Retries

For a SaaS at $20K MRR with 5% involuntary churn, reducing expired-card failures by 35% translates to roughly $350/month in prevented churn. That's $4,200/year from a feature that takes 8-15 hours to build or $19/month to buy.

Next step

Find out how many of your customers have cards expiring in the next 30 days. SaveMRR's free Revenue Scan connects to your Stripe account (read-only) and shows you exactly how many payment methods are expiring soon, your current failed payment volume, and the estimated impact of adding pre-dunning. It takes 2 minutes and helps you decide whether to build or buy a pre-dunning solution.

Frequently asked questions

Does Stripe automatically notify customers when their card is about to expire?

Stripe does not send card expiry reminders by default. It participates in Visa Account Updater and Mastercard Automatic Billing Updater which silently update some cards, but this only covers about 60-70% of US and EU cards. For the rest, you need to build your own pre-dunning email sequence or use a tool that handles it.

How many days before card expiry should I send reminders?

Send three reminders at 30, 14, and 3 days before the card expiration date. The 30-day email gets the highest conversion rate since there is no urgency stress. The 3-day email catches procrastinators. Include the card's last 4 digits and a direct link to Stripe's Billing Portal for one-click card updates.

What percentage of failed payments are caused by expired cards?

Expired credit cards cause 25-30% of all failed subscription payments, making them the single most common failure reason. Pre-dunning reminders prevent 55-65% of those failures from ever happening. For a SaaS at $20K MRR with 5% involuntary churn, that translates to roughly $350/month in prevented churn.

How do I check card expiry dates using the Stripe API?

Use stripe.paymentMethods.list() or expand the default_payment_method on subscriptions. Each payment method has card.exp_month and card.exp_year fields. Run a daily cron job comparing these dates to the current date and trigger your reminder sequence for cards expiring within 30 days.

Is it worth building pre-dunning if Stripe already has automatic card updaters?

Yes. Stripe's card updater only works for cards where the bank issues a direct replacement on the same network. It does not cover customers who switch banks, close accounts, or use card types outside the updater programs. Pre-dunning fills that gap and has a 25-35% click-through rate, which is higher than post-failure dunning emails at 15-25%.

Your Stripe has a leak. Let's find it.

Free Revenue Scan: paste your Stripe key, see every dollar you lost in 60 seconds. No card needed.

Run my free scan