- A failed payment alert fires when a charge doesn't go through — an expired card, insufficient funds, an incomplete 3-D Secure step — so you hear about it while you can still recover the customer.
- Most failed payments are involuntary. The customer never chose to leave. That makes involuntary churn a billing problem you can often fix, not a value problem — but only if you see it in time.
- Dunning is the recovery layer. Retries plus a card-update nudge quietly recover most transient failures. Stripe Smart Retries and Apple's billing retry both do real work here.
- The real-time signal already exists. Stripe emits
invoice.payment_failed; Apple emits App Store Server Notifications v2 and StoreKit 2 transactions. The gap is turning those into an alert you'll act on. - The wall: a raw processor ping knows the charge and the amount — not who the customer is across your rails, what plan they're on, or what they're about to lose.
- The join changes the alert. Because Crossdeck holds revenue, entitlements, and identity on one timeline via the cross-match, a failed charge arrives named: this customer, this plan, this access ending in N days — live to Telegram, with Prism for the follow-up.
Definitions used in this guide
A charge that did not complete — a declined renewal, an expired card, an authentication never confirmed — leaving a subscription at risk of lapsing.
A paying customer lost without a decision to leave, because a payment failed and nobody recovered it. Usually fixable — if it's caught in time.
The recovery process: retrying the charge on a schedule and nudging the customer to update their card, before access is finally cut off.
Re-attempting a failed charge over time. Stripe's Smart Retries and Apple's billing-retry period both re-run the charge for when it's likeliest to clear.
A window where the customer keeps access while the retry runs, so a transient failure doesn't interrupt service before recovery has a chance.
What a customer is currently allowed to use, based on their verified subscription. When a payment fails, the entitlement is what's about to lapse.
Joining revenue, entitlements, and identity by identity — the engine that keeps a failed charge and the customer behind it on the same record.
Ask your live Crossdeck numbers a question in plain English and have your own connected AI model answer off them. Live today in the Telegram bot's private chat.
What is a failed payment alert? The short answer
A failed payment alert is a notification that fires when a customer's charge does not go through — a renewal that declined, a card that expired, an authentication that was never completed — so you hear about it while you can still act, instead of finding out weeks later as a cancelled subscription. The whole value of the alert is timing. A failed payment has a recovery window — a few days, sometimes a couple of weeks — in which a retry or a card update can quietly save the customer. Miss it and the subscription lapses, and winning that customer back costs far more than keeping them would have.
A bare alert tells you a charge failed and how much. That's better than nothing, but the number alone doesn't say whether this is a churned trial you can ignore or a long-standing annual subscriber you should reach out to today. The useful version answers the question the raw ping can't: who failed, what plan they're on, and what access they're about to lose. First, though, the fundamentals — because you need that foundation either way.
How payments actually fail
Failed payments feel random until you look at the causes — almost all of them are ordinary, mechanical, and nobody's decision.
- Expired cards. The single most common cause, and pure friction. A card reaches its expiry date, the customer gets a new one from their bank, and simply forgets to update it. Nothing about their intent changed — but the renewal declines, and a happy subscriber is now one un-updated card away from churning.
- Insufficient funds. The charge runs at a moment the account is short and is declined. This one is often transient — the same card clears on a retry a day or two later. It is the textbook case for billing retry, and the reason retries recover so much.
- Authentication (3-D Secure / SCA). Under Strong Customer Authentication, some charges require the cardholder to actively confirm — a bank prompt, an app approval. If that step is never completed, the payment fails even though the card is perfectly good. These need the customer to act, which makes reaching them quickly especially valuable.
- Bank rules and network hiccups. A bank declines a charge its risk rules didn't like, a card is reported lost and replaced, or a processor timeout trips. Some resolve on retry; some need the customer to intervene — which is why triaging by cause matters.
Involuntary vs voluntary churn
Churn splits into two kinds that need opposite responses, and conflating them is a costly mistake. Voluntary churn is when a customer decides to leave — they cancel, downgrade, or deliberately let a plan lapse. Involuntary churn is when a paying customer loses access without ever deciding to, because a payment failed and nobody recovered it in time.
The distinction matters because the fix is different. Voluntary churn is a product and value conversation — the answer lives in the product. Involuntary churn is a billing problem, and usually a fixable one: a subscriber lost to an expired card is not a verdict on your product; it's a card that rolled over while your recovery process either didn't exist or didn't reach them. Treating it as a value problem sends you off improving features when the leak is in billing.
Involuntary churn is dangerous precisely because it is invisible by default. A voluntary cancellation at least produces a signal — a cancel click, sometimes a reason. An involuntary loss produces silence: a charge quietly fails, retries quietly exhaust, access quietly ends, and the first you hear of it is a smaller number at month-end with no name attached. A failed payment alert is what gives involuntary churn a voice — turning a silent leak into a named, timely event. It's also only half the churn picture; the behavioural side — customers drifting away before they cancel — is its own discipline, covered in how to reduce subscription churn by understanding product behavior.
Dunning and billing retry, across rails
Between a failed charge and lost revenue sits a recovery layer. Dunning is the process of recovering a failed payment: retrying the charge on a schedule, asking the customer to update their card, and deciding how long to keep access on while you try. Because so many failures are transient — insufficient funds today, cleared tomorrow — a sensible retry schedule quietly recovers a large fraction of them without the customer ever noticing. It is the difference between a failed charge and a churned customer.
Both major rails already do this in near-real-time, and each emits a signal you can listen to. The full how-to lives in how to monitor failed payments and billing retry in your app; the summary here is brief.
Stripe. When a subscription charge fails, Stripe moves the invoice to past_due and retries it. Smart Retries times the re-attempts using signals from across its network — aiming for when a charge is likeliest to clear rather than at fixed intervals — and Stripe can send dunning emails asking the customer to update their card, with your choice of what happens when retries are exhausted. Critically, Stripe emits webhook events at each step — invoice.payment_failed, the move to past_due — so the moment a payment fails is knowable in real time, not something you wait for a report to reveal.
Apple. App Store subscriptions have their own recovery: when a renewal fails, Apple enters a billing retry period and re-attempts the charge over time, optionally with a grace period that keeps access on while it tries. And — the part founders often miss — Apple signals all of it in near-real-time through App Store Server Notifications v2 and StoreKit 2, with events such as DID_FAIL_TO_RENEW and GRACE_PERIOD. The real-time signal exists. What lags is App Store Connect's own reporting — sales and financial reports trail by a day or more — so a founder watching only the Connect dashboard can wait to learn a renewal failed, even though the notification went out much earlier.
| Stripe | Apple (App Store) | |
|---|---|---|
| Retries a failed charge? | Yes — Smart Retries | Yes — billing retry period |
| Keeps access during retry? | Your dunning config | Optional grace period |
| Nudges the customer? | Dunning emails | Apple prompts to update payment |
| Real-time failure signal? | invoice.payment_failed webhook | Server Notifications v2 / StoreKit 2 |
| What actually lags | Nothing — webhook is immediate | Connect reporting, not the notification |
Both processors give you a fast, honest signal that a payment failed, and both run their own recovery. What neither does — because it isn't their job — is tell you who that customer is across your whole business, or what they're about to lose. That's the gap the rest of this guide is about.
How you'd find out today
Given the signal exists, how do founders actually learn a payment failed? Three common ways, each with a real limit.
- Processor emails. Stripe emails you and the customer; Apple prompts the customer to update payment. Fine at a handful a month. At volume it's hard to triage — every failure looks the same in an inbox, the important annual subscriber sits beside a churned trial, and the whole stream is one filter rule from a folder you stop opening.
- The dashboard. Stripe shows failed and past-due invoices; App Store Connect shows subscription status once its reports catch up. Both work — if you remember to look. A dashboard is a place you go, not a thing that reaches you, so it catches the failures you already worried about and misses the ones you didn't.
- Do-it-yourself webhooks. The real-time route: listen to
invoice.payment_failed(and the App Store equivalents) and route a message to Slack, email, or a chat app. This gets you a genuine live ping, and for a single-processor business it can be enough. We wrote the practical build-out in how to monitor failed payments and billing retry in your app.
The DIY ping is the best of the three, and still limited: out of the box the webhook knows only what the processor knows — a charge, an amount, a customer id on that rail — not who the customer is across your other rails, what plan they're on, or what access lapses if recovery fails. You get a real-time "a charge failed," which is the top half of an alert. The bottom half is a join the processor was never built to make.
The wall: a ping that can't name the customer
Here is the crux, stated plainly: a raw payment-failed ping can tell you a charge bounced and for how much, but not who the customer is across your rails, what they're entitled to, or what they're about to lose — because it holds the charge, not the customer. This isn't a shortcoming Stripe or Apple forgot to fix. A payment processor is a system of record for charges. What plan a person is on, how long they've been a customer, and what their subscription grants across web and mobile is a different question, held in a different place — and the join between them doesn't exist unless something builds it.
You can attach a customer id to the webhook, yes — but an id is a pointer, not an answer. To turn "customer cus_8842's charge failed" into "a two-year annual subscriber worth about $X in recognised revenue, whose access ends in nine days," you pull the matching records from your billing rails and the app stores, cross-reference which entitlement is at risk, and assemble the picture by hand — in the exact recovery window when you can least afford the delay. The question "is this a customer I should fight to keep?" should take seconds; stitched across three tools it takes an afternoon and a caveat.
| What the alert tells you | Bare processor ping | Identity-joined alert |
|---|---|---|
| A charge failed | Yes | Yes |
| The amount | Yes | Yes — plus recognised revenue at risk |
| Which customer, across rails | An id on one rail | Named, joined by identity |
| What plan they're on | Not held | The verified plan |
| The access about to lapse | Not held | The entitlement at risk |
| How long until it's lost | Unknown | Retry window / grace period |
| How you triage | By amount, one charge at a time | By customer value and access at risk |
The top rows are a near-tie — everyone knows a charge failed and for how much. What separates the two columns is the bottom block: which customer, what they're on, what lapses, and how long you have. That's not a backlog gap; it's what each system was built to know.
The alert that names the customer and the access at risk
Everything above points at one missing capability. A raw ping can't say whose access is at risk because the charge and the customer live in different databases with no shared identity. Crossdeck joins revenue, entitlements, and identity by identity — the cross-match — so a failed charge arrives already attached to the paying customer, their verified plan, and the access about to lapse. The join isn't reconstructed; it was never separated.
That one architectural fact rewrites the alert. Instead of "charge ch_1P… failed, $—," it can read, in an illustrative shape drawn from your own live numbers: "a renewal just failed for a customer on the annual plan — about $X in recognised revenue, access ends in N days if it isn't recovered." Same underlying failure, captured from the same webhook a DIY setup would use, but presented as a customer at risk — so you triage by who's worth reaching out to and how long you have, not by anonymous charge. Every figure is read from live Crossdeck data across your rails, never an estimate. And because the same join stamps errors too, a checkout error and a failed renewal for the same person land on one timeline — the thread in error alerts that name the customers affected.
Multi-rail, and honest about what it does
The join is what makes the multi-rail picture coherent. A customer might pay through Stripe on the web and the App Store on their phone; to a pair of raw webhooks those are two unrelated ids, but to the cross-match they're one person with one entitlement, and a failed renewal on either rail is a failure against the same customer. One caveat, stated plainly because accuracy matters: Crossdeck reads and verifies these signals — it does not change them. It surfaces Apple's already-emitted notification before the Connect dashboard catches up, and reads Stripe's webhook the instant it fires; it does not speed up a payout, alter a retry schedule, or move money. Recovery is still Stripe's and Apple's to run; Crossdeck's job is to make sure you know who's at risk, in time.
Delivered to Telegram, Prism for the follow-ups
An alert is only as good as its odds of being seen. Crossdeck delivers these alerts to Telegram, in a private chat with its bot, on the phone you already carry — no separate billing console to open. In that private chat the bot's alerts, its Mini App dashboard, and its hard-data commands — /status, /revenue (this month's recognised revenue), /people, /errors — are all live today. Team and group-chat delivery — a shared group where the whole team gets the alert and asks Prism together — is on the roadmap; for now the bot works in your own private chat.
The alert lands there as a plain-language message: what failed, for which customer, what plan, and what's at risk. The natural next question — which customers are in billing retry right now, and which are worth chasing first? — is where Prism comes in. Prism lets you ask your live Crossdeck numbers a question in plain English, right in the chat, and get an answer computed off your real data — which past-due customers hold the most recognised revenue, or which failed renewals are closest to losing access.
Two honest notes on how Prism works. First, Prism runs on your own connected AI model, using your own key — you bring the model; it answers off your live Crossdeck numbers. It is your model reading your data, not a Crossdeck-run model, and nothing trains on what it reads. Second, Prism needs that model connected in the Prism tab first — a one-time setup, not a zero-config trick. You can see how it works on the Prism product page. If routing these alerts into Telegram is specifically what you're here for, the step-by-step setup lives in get Stripe error alerts in Telegram.
How to start
The move here isn't to replace your processor's dunning — Stripe and Apple do real recovery work you should keep running. It's to add the layer that names the customer, so you know who to fight for. A sensible order:
- Let the rails do their recovery. Configure Stripe's Smart Retries and dunning emails, and rely on Apple's billing retry and grace period. Most transient failures recover here without you lifting a finger; the full setup is in how to monitor failed payments and billing retry.
- Get a real-time failure signal. Don't wait for a monthly report. Listen to
invoice.payment_failedand the App Store notifications so a failure is knowable the moment it happens, not weeks later. - Add the identity join. Point those failures at a system that joins each charge to the customer, their verified plan, and their entitlement — so "who is this and what do they lose" is answered on the record instead of reconstructed by hand across three tools.
- Route the named alerts to where you'll act. Put the customer-aware alert on your phone, in plain language, with the access-at-risk in the message and Prism a question away for "who's worth saving first."
Steps one and two are table stakes and largely free — do them regardless. Steps three and four are where the identity join earns its place: the difference between an alert that says a charge failed and one that says which customer you're about to lose.
Where Crossdeck fits
To be straight about it: if all you need is to recover transient declines, your processor's dunning already does most of that. Crossdeck is the app intelligence layer above the single-purpose tools — it joins your revenue, entitlements, errors, analytics, and identity by identity, the cross-match, so a failed charge arrives already attached to the customer and the access behind it. Every other tool tells you what happened; Crossdeck also tells you who and what's at risk, because it holds the charge, the plan, and the identity in one hand rather than three.
Recovering a bounced charge is a solved problem. The unsolved one — the problem that quietly costs founders their best customers — is that the failure notification can't tell you whose access is about to end, so involuntary churn stays invisible until it's happened. Crossdeck closes that gap and delivers the result to your phone, in plain language, across Apple and Stripe, with Prism for the follow-up. You can see the platform at cross-deck.com, start with the wider picture in real-time business monitoring, or start free.
Frequently asked questions
What is a failed payment alert?
A failed payment alert is a notification that fires when a customer's charge does not go through — a subscription renewal that declined, a card that expired, an authentication that was never completed — so you hear about it while you can still act, instead of discovering it weeks later as a cancelled subscription. A bare alert tells you a charge failed and how much. A useful one goes further and names who failed, what plan they are on, and what access they are about to lose, so the failure reads as a customer at risk rather than a line in a ledger.
What causes a payment to fail?
Most failed payments come from a small set of ordinary causes. An expired card is the single most common: the customer never chose to leave, their card simply rolled over to a new expiry date. Insufficient funds is next — the charge is declined at the moment it runs and often succeeds on a later retry. Then there is authentication: under 3-D Secure and Strong Customer Authentication, some charges need the cardholder to confirm, and if that step is never completed the payment fails. Bank fraud rules, a frozen or replaced card, and processor timeouts round out the list. The important pattern is that almost none of these are a decision to cancel — they are involuntary, which is exactly why an early alert can save the customer.
What is the difference between involuntary and voluntary churn?
Voluntary churn is when a customer decides to leave — they cancel, downgrade, or let a plan lapse on purpose. Involuntary churn is when a paying customer loses access without ever deciding to: a renewal fails on an expired card or insufficient funds, no one recovers it, and the subscription quietly ends. The two need opposite responses. Voluntary churn is a product and value conversation. Involuntary churn is a billing problem — usually a fixable one — and it is often a large share of total churn precisely because it is invisible. A customer who would happily have kept paying is lost to a card that rolled over, and no one noticed in time.
What is dunning?
Dunning is the process of recovering a failed payment: retrying the charge on a schedule, emailing the customer to ask them to update their card, and deciding how long to keep access on while you try before you finally cut it off. Good dunning quietly recovers a large fraction of involuntary failures without the customer ever noticing, because most failures are transient — a card with funds a day later, a re-run that clears. Dunning is the difference between a failed charge and lost revenue; it is the recovery layer that sits between the two.
How does Stripe retry a failed payment?
When a subscription charge fails, Stripe moves the invoice to past_due and retries it on a schedule — Smart Retries uses signals from across its network to time the re-attempts for when they are most likely to succeed, rather than at fixed intervals. Alongside the retries, Stripe can send dunning emails asking the customer to update their card, and you configure what happens when retries are exhausted — mark the subscription unpaid or cancel it. Stripe emits webhook events at each step (invoice.payment_failed, the subscription moving to past_due) that you can listen to in order to know the moment a payment fails, rather than waiting for a dashboard or a monthly report.
Does Apple retry failed subscription payments?
Yes. When an App Store subscription renewal fails, Apple enters a billing retry period and re-attempts the charge over time, optionally with a grace period during which the customer keeps access while Apple keeps trying. Apple signals all of this in near-real-time through App Store Server Notifications v2 — events such as DID_FAIL_TO_RENEW and GRACE_PERIOD — and through StoreKit 2 transactions. So the real-time signal exists; the friction is that App Store Connect's own reporting lags, so a founder watching only the dashboard can wait a day or more to learn a renewal failed. A tool that ingests and verifies those notifications can surface the failure long before the Connect reports catch up.
How do you find out when a Stripe payment fails today?
There are three common ways. Stripe emails you and the customer, which is fine for a handful of failures but hard to triage at volume and easy to filter into a folder you stop reading. The Stripe dashboard shows failed and past-due invoices if you go and look, which means you have to remember to look. Or you build it yourself: listen to the invoice.payment_failed webhook and route a message to Slack, email, or a chat app. The DIY route gives you a real-time ping, but out of the box that ping knows only what Stripe knows — the charge and the amount — not who the customer is across your other rails, what plan they are on, or what they are about to lose.
Can a failed payment alert name the customer and the access at risk?
Only if the system firing the alert holds the customer's identity, their entitlements, and their revenue on the same record as the failed charge. A raw processor webhook holds the charge, not the person behind it across rails, so it cannot. Because Crossdeck joins revenue, entitlements, and identity by identity — the cross-match — a failed charge arrives already attached to the paying customer, their plan, and the access about to lapse. The alert can read, in an illustrative shape drawn from your own live numbers, "a renewal just failed for a customer on the annual plan — about $X in recognised revenue, access ends in N days if it isn't recovered," so you act on a named customer rather than a line item.
See it live on your own numbers
Connect your rails and get real-time alerts that name the customer, the plan, and the money — plus a Mini App and plain-English answers, live in Telegram. Free to start.