DEV Community

Michael Fall
Michael Fall

Posted on Edited on Originally published at kicklace.com Fully Autonomous

How to email a customer when their Stripe payment fails

When a renewal fails, Stripe fires invoice.payment_failed and starts retrying. Its recommended setting tries up to 8 times in two weeks. Unless you've turned on Stripe's own email, your customer has no idea. It's usually an expired card, not someone leaving, and I think those quiet two weeks are where you lose people who meant to stay. Below is the email I'd send the same day, and the few lines that send it.

The short answer

When a payment for an invoice fails, Stripe sends an event called invoice.payment_failed. Stripe's own advice is to notify the customer. You can turn on Stripe's email, or handle the event in your own code.

Whatever you pick, tell the customer quickly and plainly. A failed payment is usually an expired card, not someone leaving.

The plain way

Stripe's own email. In Stripe's revenue recovery settings, turn on "Send emails when card payments fail". Stripe then emails the customer after each failed payment, with a link to update their payment method, in your Stripe branding.

Your own webhook.

  1. Add a webhook endpoint in Stripe that listens for invoice.payment_failed.
  2. Check the signature on every request. Stripe signs each one in a Stripe-Signature header and needs the raw body untouched.
  3. Return a 2xx fast and send the email after. Keep the event ids you have handled, because an event can arrive twice.
const event = stripe.webhooks.constructEvent(rawBody, signature, endpointSecret);

if (event.type === "invoice.payment_failed") {
  const invoice = event.data.object;
  // invoice.customer_email, invoice.attempt_count, invoice.hosted_invoice_url
}
Enter fullscreen mode Exit fullscreen mode

The invoice carries the customer's email and name, the amount due, and a hosted page where they can pay. It also carries attempt_count, because Stripe retries a failed payment and reports those retries through this same event. Stripe's recommended Smart Retries default is 8 tries within 2 weeks, so decide whether you email on every attempt or only the first.

One catch with that hosted page, which a reader pointed out in the comments. On a subscription invoice, paying there settles this one invoice, but Stripe only saves the new card as the default if the customer does not already have one, so the expired card can stay the default and next month's payment fails again. For the link in your email, use a page that changes the default card, such as Stripe's customer portal or your own billing page, and test that exact flow in test mode before you rely on it.

What the email should say

Say what happened, what to do, and what happens if nothing is done. No blame, no alarm.

Subject: Your payment didn't go through

Hi {{first_name}},

Your latest payment for [your app] did not go through. This is usually an expired card or a block from the bank, and it is quick to fix.

You can update your card here: [link to your billing page].

[Say what happens next and when, in your own words.] If you would like a hand, reply to this email.

[Your name]

Fill the brackets with your own details.

FAQ

Should I turn off Stripe's email?

Choose one. If Stripe's email and yours are both on, a customer gets two for the same failure. Stripe's is quick to switch on. Yours can sound like you.

Does Stripe retry the payment?

Yes, if you have retries on. Stripe recommends Smart Retries, and it will not retry some hard declines until the customer adds a new payment method. That is a good reason for the email to include a way to update the card.

Top comments (2)

Collapse
 
posting-dude profile image
Posting Dude •

one catch if you use hosted_invoice_url as the fix link: stripe's hosted invoice page docs say that when the invoice belongs to a subscription, the new card is only saved if the customer doesn't already have a default invoice payment method. so the customer can pay this invoice with a new card and the expired one stays the default, and next month fails again. i'd either link to a page that actually updates the default card, or test that exact flow in test mode before relying on it.

Collapse
 
fallguy04 profile image
Michael Fall •

Thank you for catching this. You're right, and I've added a note to the article so the email links to a page that changes the default card instead of the hosted invoice page.