Flagging a Support Ticket That Arrives Right After a Failed Stripe Payment
The customer's email is the one field both systems already carry, so match them by hand on that. When a ticket comes in, search Stripe for that address and check whether an invoice.payment_failed event fired for it recently. If one did, tag the ticket and say so in a reply or an internal note before anyone spends time treating a billing problem like a product bug.
Nothing does this automatically by default. Stripe doesn't know your support tool exists, and your support tool has no idea what Stripe is doing to a customer's subscription in the background. The two systems run in parallel, and the only thing connecting a failed charge to the ticket that shows up nine minutes later is whether a person happens to check.
What Stripe already knows that the ticket doesn't
A failed subscription charge fires invoice.payment_failed, and the event carries an attempt_count telling you which try this was and a next_payment_attempt telling you when Stripe will try again, per the subscription webhooks guide. A failed one-time charge fires charge.failed instead. Either way, the customer usually finds out too, because Stripe's automatic email notifications can send a message the moment a payment fails, separate from anything your support team writes.
If you've turned on Smart Retries, the default policy tries the charge again up to 8 times over 2 weeks, timed by a model that looks for the moment a retry is most likely to succeed. The subscription sits in past_due while that plays out. What happens to the customer's access during past_due isn't a Stripe setting, it's a decision your own product made, usually by keying some feature off subscription.status. Plenty of products quietly restrict something once that status flips, a report stops generating, a sync pauses, an export button disables, and the person on the other end just sees a thing that used to work suddenly not working.
None of that context rides along into a support ticket. A ticket has a requester, a subject, and a body. Zendesk's ticket tags can carry a billing flag once someone (or something) sets it, but nothing sets it by default, and the same is true of whatever ticketing tool you run. The billing event and the ticket are facts about the same account, sitting in two systems that have no reason to talk to each other unless you make them.
The habit: check before you troubleshoot
The manual version is one lookup, run at the moment a ticket lands. Stripe's Customer Search API supports an exact match on email:
GET /v1/customers/search?query=email:'requester@example.com'Pull that customer's subscription and look at its status and, if it's past_due, the invoice's attempt_count and next_payment_attempt. If the failure happened recently, minutes or hours before the ticket, not weeks, tag the ticket (billing-payment-failed or whatever your taxonomy uses) and drop a note listing which card, which attempt number, and when Stripe tries again. That note is the only thing that tells the next person to look at this ticket that it isn't what it looks like.
The recency window matters more than it seems. A card that failed three weeks ago and quietly got fixed on retry two isn't relevant to today's ticket; a card that failed nine minutes ago almost certainly is. Anchor the check to whatever your past_due window actually is, not to "any failure ever."
Three places the manual check falls short
The lookup takes under a minute and works fine for a handful of tickets a day. It breaks down the same way every manual correlation does:
- It depends on someone remembering to run it, on every ticket, before assuming the report is a real bug. A ticket that reads as clearly billing-shaped gets checked; one that reads like a generic glitch often doesn't.
- The recency window is a judgment call nobody's written down. Nine minutes is an easy match. Two days is a coin flip that different agents will call differently.
- It only catches the direction where the ticket arrives after the failure. A customer who emails first and gets a dunning email an hour later never gets the reverse check, unless someone goes looking a second time.
Rather than have someone run a Stripe search per ticket, teams push the connection into the account record directly. Modem reads failed payments as one of five billing-event triggers on its Stripe integration, matching the Stripe customer to the same person and company record built from every other connected tool, support tickets included. When a payment fails, that fact sits on the account already, so a ticket that lands nine minutes later shows up next to it instead of needing a separate lookup to explain itself.
Modem is the company behind this guide, and that's worth naming plainly. The same tradeoff sits underneath every tool that promises to connect two systems automatically, ours included, a Zendesk app, or an internal script someone builds in a weekend. What changes between them is who has to remember to run the check when nothing is automated. The manual lookup above costs nothing to try today. Automating it costs a setup step now, in exchange for not needing anyone to remember it on ticket four thousand.
Related reading: how to tell if the customer emailing support is your biggest Stripe account covers the same kind of billing-to-ticket lookup for account size instead of payment status, and how to alert your team when a high-value account downgrades covers the churn-signal side of the same webhook family.
Put the recency rule in the runbook
Write the recency rule down (anything failed in the last hour counts, anything older gets a fresh look) and put the Stripe email-search step into whatever runbook new support hires read on day one. That's what turns "is this actually a bug" from a guess into a one-minute check, before anyone opens a debugging session over what's actually an expired card.
