How Supertype recovers lost sales with Slack webhooks
A failed Stripe payment is your warmest lead, a customer who chose the plan and tried to pay in the last few minutes. Here is how Supertype recovers those lost sales by sending charge.failed webhooks straight into Slack, with the product, amount, decline reason, and customer contact ready to act on.
Most conversations about cart abandonment stop at the shopping cart. Someone adds a plan to their basket, gets pulled into a meeting, and never comes back, so the growth team queues a reminder email for the next morning. There is a second kind of abandonment that costs more and receives far less attention, and it happens after the customer has already decided to buy. They reach the payment step, they enter a card, and the charge fails. The intent was there, the money simply did not move, and in most businesses that moment disappears into a Stripe dashboard that nobody watches in real time. At Supertype we build Viably, and we also sell our own products on Stripe, so we felt this gap from both sides. This is how we started recovering those lost sales by sending Stripe webhooks directly into Slack.
Cart abandonment does not end at the checkout page
When people talk about cart recovery they usually mean the top of the funnel, the browser who filled a basket and wandered off. The failures that hurt most sit one step later, at the card form, where someone who genuinely wanted to pay was stopped by something small. It might be a card without the funds to cover it that day, a mistyped security code, an expired card the customer never got around to updating, or a bank that declined an unfamiliar charge out of caution. None of these people changed their mind about your product. They ran into a mechanical problem between wanting to pay and actually paying, and a meaningful share of them will complete the purchase if you reach them while the decision is still warm. The willingness to recover these sales has never been the hard part. The hard part is that the signal you need arrives somewhere your team never looks.
Why a failed charge is your warmest lead
A marketing qualified lead is a stranger who might, someday, be interested. A failed charge is a person who read your pricing, chose a plan, entered their details, and tried to hand you money in the last few minutes. On any honest measure of intent the second is worth far more than the first, and yet most teams pour effort into the top of the funnel while the bottom leaks quietly. The reasons a charge fails are usually mundane and, more importantly, fixable with a short and human message. A note that says the payment for the annual plan did not go through because the card was declined, and asks whether they would like to try another, lands very differently when it arrives an hour after the attempt rather than a week later inside an automated sequence. Speed and specificity are what make recovery work, and both of them depend on your team learning about the failure quickly and knowing enough about it to say something genuinely useful.
Putting Stripe webhooks directly in Slack
The mechanism we settled on is simple to describe. Stripe emits a charge.failed event every time a payment attempt fails, and that event already carries almost everything you need to act. We forward it into the channel where our customer care and growth people spend their day, using Viably's webhook relay. Stripe posts the event to a signed URL, Viably verifies the signature so you can trust that the request genuinely came from Stripe, and the raw JSON becomes a clean Block Kit card rather than a wall of fields. Because Stripe webhook destinations send a plain POST and cannot attach an authorization header, the relay accepts the token as a query parameter, so even a rigid sender integrates without a proxy standing in front of it. The full walkthrough lives in the Stripe to Slack guide, and the same relay handles your successful charges and subscription events alongside the failures.
What a recovery alert needs to show
A notification that only says a payment failed is almost useless, because the person reading it still has to open Stripe, find the charge, and reconstruct what happened. The card we post is built so that whoever sees it can act without leaving Slack. It leads with the product the customer was trying to buy, resolved from the Stripe metadata you already set and falling back to the charge description and then the statement descriptor, so the card always names what was at stake. The amount sits alongside it, which tells the reader in an instant whether this is a nine dollar event ticket or a nine hundred dollar annual renewal. The decline reason comes through in plain language, carrying both the machine code such as card_declined and the human sentence such as "Your card has insufficient funds," because the wording of your outreach should follow from why the payment actually failed. And the customer's own details, their name, email, phone, and location, are right there, so reaching out becomes a matter of clicking rather than hunting.
That last part is where the enrichment earns its keep. Subscription charges in particular often arrive with an empty billing name, because the payment was taken against a saved customer rather than a freshly filled form. Viably remembers the contact details from that customer's earlier successful invoice and quietly fills the gaps, so a failed renewal still shows you a real person to talk to instead of a bare cus_ identifier. Stripe webhooks directly in Slack are only worth having if the message is complete, and completeness here comes from stitching the failure together with everything else Stripe has already told you about that customer.
Turning the alert into an owned recovery task
An alert that everyone sees and nobody owns tends to evaporate in exactly the way the failure would have on its own, only more visibly. This is why every failed charge can open a follow-up task at the same moment it posts, and for new Stripe endpoints that behaviour is on by default. The task lands as a card underneath the alert, and you can assign it to a specific person in customer care or leave it up for grabs for whoever is free to claim it in Slack. The effect is that a decline stops being a fact that flickers past in a busy channel and becomes a small, tracked piece of work with a name attached and a definite ending, either the sale is recovered or it is deliberately set aside. We wrote at more length about why owned follow-up separates a toy integration from real workflow in building an event-driven workforce, and failed payments are the case where that principle pays for itself fastest.
Keeping the recovery signal clean
There is a failure mode that quietly kills channels like this, and it is noise. A customer whose card is genuinely broken will not fail once. They will fail again when Stripe retries the subscription invoice that evening, and again the next morning, and a checkout shopper repeatedly submitting a declined card can produce a small burst of near identical events inside a single minute. If each of those posted its own alert and spawned its own task, the channel would become something people mute within a week, and a muted recovery channel recovers nothing. So Viably collapses the noise by identity. After the first charge.failed for a given customer, further failures for that same customer are held quietly for a day, which folds dunning retries and repeat attempts into the single alert and the single task you already have open. For anonymous checkouts with no customer attached, the same suppression works on the payment intent instead. What you are left with is one clear signal per customer per day, which happens to be the cadence a human recovery workflow can actually sustain. Failed charges are also kept out of your revenue totals and periodic reports, so an attempted payment never inflates a number that should only ever count money that arrived.
How to set up failed payment recovery in Slack
Standing this up took us a few minutes and no new infrastructure. Inside Slack you run /webhook-relay and create a Stripe Transactions endpoint, which hands you a signed relay URL. In your Stripe dashboard you add that URL as a webhook destination and choose the events you care about, then you paste the signing secret back into Viably so every incoming request is verified. For recovery you want charge.failed alongside the events that make the successful side work.
charge.succeeded required
charge.failed recovery
invoice.paid required
customer.subscription.updated optional
charge.succeeded posts the wins and, together with invoice.paid, seeds the customer contact details that later enrich a failure. charge.failed is the one that converts a lost sale into an alert and a task. All of this runs on the free plan, verification and retries and logs included, so you can watch a test decline land in your own channel before it ever costs anything.
What cart recovery in Slack unlocks
Once failed payments surface where your team already works, several things shift beyond the recovered charges themselves. Outreach gets faster, because the person who can help sees the problem within seconds instead of at the end of a weekly reconciliation. The tone gets warmer, because the message is written by someone who can see the customer's name and the reason their card was declined rather than generated by a sequence that treats every failure alike. Over a few weeks you also begin to read patterns in the failures, noticing which cards decline most often, whether certain regions struggle more than others, and whether a particular plan sees more abandonment at the payment step, and those patterns become the raw material for fixing the checkout rather than forever patching its aftermath. Cart abandonment recovery stops being a quarterly clean up exercise and becomes a steady habit that runs in the same room as the rest of your operations.
If you sell on Stripe and you have never watched a failed payment arrive in the channel where your team could actually do something about it, that is the quickest place to feel the value. Add Viably to Slack, run /webhook-relay, and point your first charge.failed event at a channel. The lost sale you recover in the first week tends to pay for the setup many times over.