Episode 5·

Stop Chasing Invoices: Zero-Touch Dunning with Stripe Smart Retries

Intro

If you're running recurring revenue through Stripe without a structured dunning system, you're leaving actual money on the table every quarter. This episode is for solo operators who want to automate payment recovery without hiring collections staff or having awkward client conversations.

In This Episode

Jordan demonstrates building a complete zero-touch dunning system that combines Stripe Smart Retries with webhook-driven automation through Make or Zapier. You'll see the exact Dashboard configuration for 8 retry attempts over 2 weeks, the webhook events that trigger customer emails and internal alerts, Notion database setup for tracking recovery status, and Test Clock validation to prove it works before going live. The episode covers ACH Direct Debit special handling, idempotency patterns to prevent duplicate processing, and a client-facing Payment Reliability Score dashboard that makes invisible automation visible to clients.

Key Takeaways

  • Configure Stripe Smart Retries for 8 attempts over 2 weeks with 'Mark as unpaid' end-state to automatically recover failed payments without manual intervention
  • Build webhook orchestration using invoice.payment_failed events and attempt_count to trigger escalating customer communications and internal Slack alerts
  • Create a Payment Reliability Score dashboard in Notion that shows clients their payment success rate and motivates proactive payment method updates

Timestamps

Jordan: Nine dollars recovered for every dollar spent on billing. That's what Stripe reports for Smart Retries. Deliveroo recovered over a hundred million pounds in one year. Retool pulled back six hundred and thirty thousand dollars.

And here's what kills me — most solo operators are still manually chasing invoices. Still sending those awkward "hey, your card declined" emails at ten PM. Still losing fifteen percent of their MRR to failed payments they never even try to recover.

I was looking at my Stripe dashboard last week. February alone — forty-seven hundred dollars recovered automatically. Zero emails sent by me. Zero uncomfortable client conversations. Just Smart Retries doing its thing while I was working on actual client deliverables.

The entire recovery system — webhooks, customer emails, Slack alerts, Notion updates — takes about ninety minutes to build. And once it's running, you literally never touch it again.

Today I'm showing you exactly how to build this. The precise Dashboard settings, the webhook events you need, the Make scenarios that handle the orchestration. We're even going to test it with Stripe Test Clocks so you know it works before a real payment fails.

Jordan: If you're running recurring revenue through Stripe and you don't have a structured dunning system with Smart Retries configured, you are leaving thousands on the table every quarter. Not potential revenue — actual revenue from clients who want to pay you but whose cards are failing. By the end of this episode, you'll have that system. Zero manual work, zero awkward conversations, just recovered revenue hitting your account while you focus on delivery.

Jordan: Okay, so here's what actually happens when you don't have dunning set up properly. A client's card expires. Or they get a new card number. Or their bank flags the charge for some random fraud prevention reason. The payment fails. And then... nothing. Stripe tries once, maybe twice with their default settings, and then the subscription just sits there. Past due. The client doesn't even know there's a problem because Stripe's default email — if it even sends — lands in spam. Meanwhile, you're delivering work for free.

I had a client last year — twelve hundred a month retainer, rock solid for eight months. Then their CFO changed the company card without telling anyone. Payment failed. I didn't notice for six weeks. Seven thousand two hundred dollars of work delivered while their subscription sat in past_due status. And when I finally reached out? "Oh, we thought you paused the service."

Here's what we're building today to prevent that. First, we're going to configure Smart Retries in your Stripe Dashboard — and I mean actually configure it, not just leave the defaults. Eight attempts over two weeks, with specific end-state handling. Then we're setting up the webhook layer in Make that catches every payment event and orchestrates the response. Customer emails that actually land. Slack alerts so you know immediately when something fails. And — this is crucial — Notion updates that track recovery status so you can see exactly what's happening with every failed payment.

Let me show you exactly how this works in production.

Jordan: Alright, first thing — go to your Stripe Dashboard. Not the API settings, not billing, the actual Dashboard home. Click Billing in the left nav, then Revenue recovery, then Retries. This is where most people get stuck, so let's slow down.

You've got two different retry configurations here. Subscription retries and one-off invoice retries. We care about both, but they live in different places. Subscription retries are right here under Revenue recovery. One-off invoice retries — those are under Settings, then Billing, then Invoices, then Advanced invoicing features. Yeah, it's buried. That's why nobody configures it.

For subscriptions, Stripe recommends eight attempts within two weeks. But look at these options — you can do one to two weeks, three weeks, even one to two months. Here's what actually happens with each setting. The ML model — and yes, it's actually ML-driven, not just a timer — looks at network-wide signals. Time of day the card usually works. Whether it's a debit or credit card. The specific decline code. Then it picks optimal retry times within your window.

Eight attempts in two weeks is the sweet spot. Shorter and you miss recoveries from temporary holds. Longer and the client genuinely thinks you've stopped service. Set it to eight and two weeks.

Now here's the critical part nobody talks about — the end state. When all retries fail, what happens? You've got three options. Cancel the subscription — clean but harsh. Mark as unpaid — keeps it active but blocks access. Leave as past_due — dangerous because they keep getting service. I use "Mark as unpaid" for everything except true enterprise accounts. It's clear, it's reversible, and it stops delivery without burning bridges.

Jordan: Okay, Smart Retries are configured. Now we need the webhook layer. Because here's the thing — Stripe will retry the payment, but those default emails? They're terrible. Generic, often caught by spam filters, and they don't create urgency. We're going to build something better.

Go to Make.com — or Zapier if that's your preference, the logic's the same. Create a new scenario. We're using the Stripe app, and here's why this is beautiful — Make's Stripe app provides instant triggers via webhooks. It literally attaches the webhook for you. No manual configuration in Stripe's webhook settings.

Add a Stripe module. Watch Events. Now, which events do we actually need? This is where people overthink it. You need four events, maybe five. Invoice.paymentfailed — that's your primary trigger. Invoice.paymentsucceeded — that's your recovery confirmation. Paymentintent.paymentfailed if you're handling one-off payments. Charge.failed for backup. And if you've got Automations enabled in Stripe, you also want invoice.updated because that's where nextpaymentattempt lives.

Here's the critical field everyone misses — attemptcount. It's right there in the invoice.paymentfailed webhook payload. First attempt? Send a friendly heads-up. Third attempt? Create urgency. Final attempt? That's when you send the "we're about to lose service" email.

Let me show you the actual automation logic. First module is the Stripe webhook trigger. Second module is a router with three branches based on attempt_count. Branch one — attempts one and two — sends a soft reminder email through Gmail. "Hey, your payment didn't go through, but don't worry, we'll try again automatically." Include the customer portal link so they can update their card if needed.

Branch two — attempts three through five — increases urgency. Email plus SMS if you have their number. "We've tried a few times to process your payment. To avoid service interruption, please update your payment method." Still friendly, but clear about consequences.

Branch three — attempts six through eight — this is where you pull out all stops. Email, SMS, and a Slack alert to yourself. The client message is direct: "This is our final attempt to process your payment. Update your payment method today to maintain access." And internally, you get a Slack notification that says "Client X is about to churn due to payment failure."

But here's what makes this bulletproof — idempotency. Webhooks can fire multiple times for the same event. Stripe even tells you this in their docs. So we need to make sure we don't send three copies of the same email.

Add a Data Store module in Make. Call it "Processed Stripe Events." Every time a webhook fires, check if we've seen this event.id before. If yes, stop the scenario. If no, process it and add the ID to the store. This one step prevents ninety percent of the weird edge cases people hit with payment automations.

Jordan: Now let's talk about the Notion integration. Because tracking this stuff matters. Create a database called "Payment Recovery." Fields: Client Name, Invoice ID, Failure Date, Attempt Count, Next Retry Date, Current Status, Amount, and Recovery Date.

Every time invoice.paymentfailed fires, we create or update a record. Use the invoice ID as your unique key. Update the attempt count. Pull the nextpaymentattempt from the invoice object — but remember, if you have Automations enabled, this comes through invoice.updated, not invoice.paymentfailed. When invoice.payment_succeeded fires, update the status to Recovered and log the recovery date.

This gives you a dashboard showing exactly what's at risk. You can see which payments are in retry, how many attempts are left, when the next attempt will happen. No surprises. No forgotten failures.

Jordan: Here's something most people don't know — ACH Direct Debit has completely different retry rules. Cards get eight retries over two weeks. ACH gets two retries maximum, and they have to be within forty days of the original attempt.

If you're taking ACH payments — and if you're working with larger clients, you probably should be — you need separate logic. In your Make scenario, add a condition that checks the payment method type. If it's ACH, different email copy. "ACH payments can take several days to clear. We'll retry this automatically in five business days." No panic, no urgency on the first failure. ACH failures are usually timing issues, not actual problems.

Jordan: Alright, let's test this entire flow. This is where Stripe Test Clocks become incredible. Go to your Stripe Dashboard, click Developers, then Test Clocks. Create a new test clock. Set it to today. Now create a test subscription that will renew tomorrow.

Add a test card that will fail — four zero zero zero zero zero zero zero zero two. That's the "card declined" test number. Advance the clock to tomorrow. Watch what happens. The payment fails. Your webhook fires. Check Make — the scenario should have run. Check your email — you should have the first failure notice. Check Notion — there should be a new record with attempt_count of one.

Now here's the beautiful part — advance the clock a few more days. Watch the attempt count increment. See the emails change tone. Watch the Notion record update. You can validate your entire dunning flow in about ten minutes instead of waiting two weeks to see if it actually works.

One thing to watch for — Test Clocks don't perfectly simulate Smart Retries timing. They'll retry on a schedule, but not with the ML optimization. So don't worry if the timing seems mechanical. In production, it'll be smarter.

Jordan: Okay, let me address the elephant in the room. Some people will tell you Smart Retries alone isn't enough. That you need specialized dunning tools, pause options, discount offers, win-back campaigns. And look — for a SaaS with thousands of customers, maybe. But for a solo operator with twelve to fifty clients? Smart Retries plus this webhook orchestration recovers ninety-plus percent of what's recoverable.

The failures you don't recover aren't timing issues. They're genuine problems — cancelled cards, closed accounts, clients who actually want to leave. No amount of retry optimization fixes those. What this system does is recover everything that's actually recoverable, automatically, without you having to have awkward conversations about money.

And here's the proof — I've been running this exact setup for eighteen months. My recovery rate is eighty-seven percent. Average time to recovery is four-point-two days. And the kicker? I've sent exactly zero manual payment follow-ups in that entire time. The forty-seven hundred dollars I mentioned at the start? That's just February. January was sixty-two hundred. December was almost nine thousand because of annual renewals.

Jordan: Let me show you the client proof dashboard I built in Notion. This is what I mean by making invisible work visible. Every client can see their payment history, successful charges, any retry attempts, and current status. But here's the clever part — I've got a formula field that calculates "Payment Reliability Score." It's just successful payments divided by total payment attempts, shown as a percentage.

Clients with a hundred percent score feel good about their relationship with you. Clients who see they're at seventy percent because of retry issues? They update their payment method proactively. It's amazing how effective a simple percentage can be at driving behavior.

The whole dashboard is powered by the same webhook data we're already collecting. No extra work. Just a filtered view of the Payment Recovery database, embedded in their client portal. They see their reliability score, you see recovered revenue. Everyone wins.

Jordan: One last thing about the setup — make sure you verify webhook signatures if you're using HTTP modules instead of Make's native Stripe app. Stripe signs every webhook with a secret key. If you don't verify it, someone could theoretically send fake payment failures to your endpoint.

The Make Stripe app handles this automatically. But if you're building a custom endpoint — maybe because you need more control — you have to verify that Stripe-Signature header yourself. The docs have examples in every language. Don't skip this step. Security matters, even for internal automations.

Jordan: So that's the system. Smart Retries configured for eight attempts over two weeks. Webhook orchestration through Make handling the customer communication. Notion tracking every recovery attempt. And Test Clocks to validate it all before you go live. Ninety minutes to build, runs forever, recovers thousands in revenue you're currently leaving on the table.

The download pack for this episode has everything — the exact Gmail and SMS templates for each attempt count, the Make scenario JSON you can import directly, the Notion database template with all the formulas set up, and a matrix showing optimal retry windows for different client types. Plus that Payment Reliability Score dashboard I showed you. Just duplicate it into your workspace and connect the webhook data.

Here's your action item: Go to your Stripe Dashboard right now. Check your Revenue recovery settings. If you're still on the defaults, you're losing money today that you could recover tomorrow. Configure Smart Retries. Set up the basic webhook handler. Even if you skip the Notion tracking for now, just getting Smart Retries properly configured will recover revenue immediately.

Remember — this isn't about chasing late payments. It's about building systems that protect your revenue while you focus on delivery. Every hour you spend manually following up on failed payments is an hour you're not building for clients. Automate the recovery, eliminate the friction, get back to the work that actually matters.

This is Jordan for Headcount Zero. Stop chasing invoices. Start shipping value.

stripedunningpayment recoveryautomationmake.comzapierwebhooksnotionsmart retriesfailed paymentsrevenue recoverysubscription billingsolo operatorsheadcount zero