Skip to content

Stripe events

invoice.payment_failed: what it means and what to email

Stripe sends invoice.payment_failed when a payment attempt on an invoice fails. What it means, whether Stripe emails the customer, and the email to send.

Sent
Each time a payment attempt on an invoice fails, retries included
Stripe emails
Yes, once you turn on Send emails when card payments fail
Kicklace
A failed payment, and the subscription shows past due

What it means

A payment that Stripe tried to collect on an invoice did not go through. For a subscription that can be a renewal the bank declined, or a customer who has no payment method on file to charge. Stripe sends the same event for a soft decline, which a bank may approve on a later try, as for a hard one.

The event is about one attempt, not about the customer. Someone whose card expired and someone who has decided to leave both show up here first, and only the next few days tell them apart, so the email to send is one that works for either.

When Stripe sends it

Every time a payment attempt on an invoice fails, the first attempt and every retry after it. The invoice's attempt_count says which one this was.

Stripe retries failed subscription payments on a schedule. It recommends Smart Retries, whose default is 8 tries within 2 weeks, and you can pick a period from 1 week to 2 months or write a custom schedule of up to three retries. A hard decline, such as a lost or stolen card, is not retried until the customer adds a new payment method, although the schedule keeps counting. When the last retry fails, the subscription is cancelled, marked unpaid, paused or left past due, whichever your settings say.

Like every Stripe event it can arrive more than once and out of order. Keep the ids of the events you have handled, and do not count on this one arriving before customer.subscription.updated.

Does Stripe email the customer?

Yes, if you turn it on. In Stripe's revenue recovery settings, Send emails when card payments fail makes Stripe email the customer after each failed payment, with a link to update their payment method. The link can open a Stripe-hosted page or a page of your own.

If Stripe's email and yours are both on, the customer gets two for the same failure. Pick one. Stripe's takes a minute to switch on, and yours can sound like you.

The email to send

Send the first one the same day, so the customer hears about it before the next attempt. Say what happened, what to do and what happens if nothing is done, without blame. A few days later, if attempt_count shows it is still failing, one shorter note is enough.

Link to a page that updates the card Stripe retries, such as the customer portal or your own billing page. Stripe tries the subscription's own default payment method before the customer's default, so if the subscription has one, a card saved only to the customer is not the one it retries.

Subject: Your payment for [your app] didn't go through

Hi {{first_name}},

The payment for your [your app] plan didn't go through today. It can be an expired card or a bank that wanted a second look, and a new card sorts it out.

You can update it here: [link to your billing page]. Once it is saved, the next attempt uses it. [Say when the next attempt is, and what happens to their account until then.]

If you would rather talk it through, reply to this email.

[Your name]

Other subject lines that say the same thing without alarm: "We couldn't charge your card for [your app]", "A quick note about your [your app] payment" and "Your [your app] card needs an update".

The longer version, with the code to send it yourself, is Stripe invoice.payment_failed: email the customer when a payment fails, and a copyable one is the failed payment email template.

Fields worth reading

  • customer_email and customer_name: who to write to. customer is the Stripe customer id, for looking up the rest.
  • amount_due and currency: what failed, in the smallest unit of the currency, so 4900 is 49.00 in dollars.
  • attempt_count: which attempt this was, so the first note goes once and a later one only if it keeps failing.
  • next_payment_attempt: when Stripe will try again. It is null on an invoice you send rather than charge automatically, and with Stripe's automations it is set in invoice.updated instead.
  • hosted_invoice_url: Stripe's page for the invoice.
  • billing_reason: subscription_cycle for a renewal and subscription_create for the first invoice.
  • parent.subscription_details.subscription: the subscription the invoice belongs to. Before API version 2025-03-31.basil this was subscription, which later versions removed.
if (event.type === "invoice.payment_failed") {
  const invoice = event.data.object;
  const to = invoice.customer_email;
  const attempt = invoice.attempt_count;
  const retryAt = invoice.next_payment_attempt; // unix seconds, or null
}

To see a real payload, run stripe trigger invoice.payment_failed in a sandbox and read the event it sends.

What Kicklace does

With Stripe connected, this event lands on the person as a failed payment, payment_failed, for the amount due, and the subscription shows past due. Kicklace also hears that from customer.subscription.updated, when the subscription's status turns past due, and the two are one failure: they share a key, so it lands once. A retry that fails again is a failure of its own.

A side road on your Lifecycle map can start from it. The first-run setup offers one called Card failed, and the + at the top adds one later with Payment failed as its way in. It is an account email, so Stop these emails on a tip does not hold it back, and only an address that bounced or a person who complained does. A retry that clears (an invoice.paid with an attempt_count above 1) ends the side road.

Kicklace only reads Stripe. It does not charge anyone or retry a payment, which stays with Stripe's retry settings. Nothing sends until you switch the sequence on, and before you do Kicklace shows who would have got it over the last 30 days.

Write yours from your URL. Paste your site's address into the welcome email generator and it writes the card failed email, and a shorter follow-up three days later, in your site's voice, ready to copy, with no sign-up.

Sources

Checked against Stripe’s docs on .

Free up to 1,000 contacts.

Join the journey

We're building Kicklace so you can get back to building your own product. We'll email you when there's something new worth showing.