RecoverStack

Payment recovery for bootstrapped Stripe SaaS

Visit Website
July 27, 2026 Why I run two separate email systems

This came up in someone else's thread here a few weeks ago, where I kept the details deliberately vague. Here is the full version, with names and costs.

RecoverStack sends emails from two fully separate systems, and this month I got an unplanned proof of it being a correct technical decision.

System 1 is for product email: waitlist confirmations, newsletters, and the payment-recovery emails that are integrated with the BL of the product. It runs on Resend, from the apex domain "recoverstack.dev". If these emails don't land, RecoverStack simply doesn't tick. This domain's reputation is the whole business.

System 2 is for cold outreach: Smartlead, sending from a Google Workspace mailbox on the subdomain "mail.recoverstack.dev", throttled to about 25 sends/day with warmup running. Cold email never touches the apex domain, not even once.

The reasoning is blast radius - cold email is the riskiest thing a company's email infrastructure does: a stranger who never asked to hear from you decides whether you're spam, and the sending domain absorbs every one of those judgments. Recovery emails are the exact opposite, they have to land or the product fails at its one job. Sharing a domain between those two is betting your core dependency & logic on the mood of strangers.

This month, the split got tested for real. Campaigns were running smoothly and starting to build traction, and then the suspension alert came in like thunder on a sunny day: Google had flagged the cold mailbox's logins as suspicious and suspended it. I spent three hours in Google support chats that went to the only path of deleting the mailbox entirely. This meant a new Workspace user, reconnecting Smartlead through OAuth, having the warmup history & spam-safe reputation score gone. That's a real cost, but it was contained entirely to the system that's allowed to die: the product side confirmed signups and fired drips the whole time like nothing happened.

This might surprise you, but the split cost me almost nothing extra. I needed Smartlead for the outreach automation anyway, the subdomain is a few (free) DNS records on top of the purchased domain, and finding the right setup is a quick search or one question to a coding agent. The only recurring tax is two dashboards and merging SPF entries by hand, because DNS setup wizards love to overwrite each other's records.

If you're a founder about to send your first cold campaign from the same domain your receipts and password resets use, please don't. This is one of the most damaging traps for a bootstrapped SaaS, and one of the easiest to avoid. One domain = one reputation = one point of failure. The safer setup is mostly free and a quick search away. Separate the inboxes and you'll hedge yourself from a lot of future trouble.

How is your email stack wired: one domain for everything, or split?

Comment

July 20, 2026 90 manual decisions in one "automated" run

Ten weeks ago, I ran the first end-to-end batch through my lead pipeline and logged what it actually cost me. I keep coming back to that log because the lesson hasn't changed since.

The initial setup yielded 175 raw leads aggregated from five sources, four filtering phases (a hard pre-filter for competing billing platforms, a scored rubric on subscription signals, a manual review tier, then an email resolution stage). The first version of the runbook estimated 30-45 minutes of my time per batch. The real first batch took about 4 hours.

Where did the time go? Not the scoring. The score ran fine, but 90 ambiguous rows still needed a personal include-or-reject decision, and another 71 auto-rejected rows got a second look because the cut felt too harsh to me (and 37 of them were worth recovering). Around 175 individual judgment calls in total.

Three things the numbers taught me:

Source quality beats volume: Persona-based sourcing ("works at a SaaS company") gave a 17% first-pass include rate. Filtering by detected Stripe billing gave 45%. Revenue-verified founder communities: 67%. The sources that expose the buying signal outperform the ones that expose the demographic. One batch of data, so early signal, not a conclusion.

Scoring shortcuts backfire quietly: I auto-granted points to rows from Stripe-verified sources. That correctly recovered 9 SPA-rendered sites my scanner had missed, and it also promoted 18 agencies and capital firms that use Stripe to bill clients. "Uses Stripe" and "is a subscription SaaS" look identical to pattern matching. Only reading the value prop separates them.

Automation moves the bottleneck, but it doesn't remove it: The bottleneck was never list-building, it's eyeballing. Ten weeks later, the per-batch eyeball cost is roughly the same. What I'm trying now is pointing deep-research agents at the shortlisted leads instead of pre-filtering harder, and honestly, it looks promising.

For anyone doing founder-led outbound, how do you build a filter that pre-qualifies for the buying signal instead of the persona that correlates with it? If you've cracked that, I want to hear about it.

Comment

July 13, 2026 I deleted my launch date instead of slipping it again

I deleted my launch date recently. Not slipped it, deleted it.

August 1st had been on my calendar for months. Then I looked at the numbers actually sitting behind it: about 1 genuine waitlist signup, 0 customers, 164 cold emails sent, 0 replies. A launch on August 1 would have gone out to a room with nobody in it.

The uncomfortable part is watching a date you pinned months ago drift, because the real field data is drifting under it. It is a little scary, but I think that uncertainty is just part of starting out. The real numbers are honest feedback, and looking away from them does not make them nicer.

I had written down "kill triggers" for exactly cases like this. When they started firing, they confirmed a change of direction I could already feel.

So I stopped treating the launch as a fixed date and started treating it as a lever. It gets pulled when there is actually an audience to pull it for: a real following, at least one connected merchant, one recovered dollar I can point to. Not before.

What replaced the date is a small founding cohort that runs rolling instead of opening on a single day. Every member will get 90 days for free, and then 40% off for life, locked in when they join.

If I could hand one thing to a founder about to pin their launch to a calendar: predicting demand before you have data is mostly guesswork. Once you have a little real signal, the launch call gets much easier to make honestly.

While I build toward that proof, one concrete offer: if you run a Stripe SaaS, or know someone who does, I will go through your failed-payments export by hand and send you the real number you are losing to involuntary churn, for free. You can also run it yourself from a Stripe CSV export, and I am glad to walk you through how. If that is useful, reach me at yarin@recoverstack.dev.

Comment

June 29, 2026 Reading my own numbers

I spent the weekend reading my own traction numbers instead of writing code, and they were worse than I had let myself believe.

The product is basically done. The retry engine works, the Stripe app is live, the dashboard is built. I had been treating that as progress. Then I actually looked at the demand side: 0 customers, a waitlist of basically one real signup, and 164 cold emails that produced a single reply.

The cold emails stung the most, because those leads were my strongest bet. Seeing a single reply across all of them was a real gut-punch, and once I saw that I couldn't look away from the broader patterns. The open rate had been quietly fooling me too: Around 60% "opened," which I had been reading as genuine interest, but a high open rate on a tracked email is mostly Apple Mail preloading the email, not a person reading. The really valuable metrics point to zero clicks and a single reply. Big numbers are an ego boost, and it turned out I had been chasing the wrong horse.

Here is what I think I got wrong: I built first and assumed demand would follow. It does not. A finished product nobody knows about, sold by a one-person company just starting out, asking you to connect your live Stripe account on first contact is a lot of trust to ask for before you have given anything.

So I am changing the order of work:

  • Stop building & start selling: It is so easy to get lost in your own systems, especially coming from a dev background. The job now is interacting with people, not machines.

  • Talk to people first: Offer to look at someone's failed payments by hand before asking them to install/approve anything.

  • Narrow who I reach out to, and measure replies and convos instead of posts and opens.

Taking a step back to question your own beliefs is a serious ego killer, but like eating your veggies, it is a healthy one.

I am also killing the countdown timer on the site. RecoverStack is now open to work with design partners (the founding cohort), but the hard launch happens when it is earned, not on a date I made up.

If you run a Stripe SaaS and have ever watched a renewal quietly fail, I would genuinely like to hear how you handle it.

Comment

June 22, 2026 The approval flow behind my hand-curated cohort

Last Monday I wrote about WHY the founding cohort is hand-curated instead of auto-issued. Today is the HOW: the actual approval flow, because "hand-curated" without a system is just procrastination with extra steps.

The data flow, end-to-end: A waitlist signup hits the API and lands as a row in the database, then drip Email 1 fires automatically. During my weekly review I look at who engaged (opens, clicks, and better still, a reply) and walk those rows through a four-item checklist. When approving, I run one command: npm run invite:approve along with their email. That fires the invite email with a unique code, and when they can sign up, founding_cohort = true lands on their account. That flag is what the 40%-for-life discount and the Phase-2 conversion logic key off later.

I will be honest about one thing before going further: right now "weekly review" is more aspiration than habit. Direct reply volume is still low. I just flushed out the cold campaigns, so I expect engagement to ramp and the cadence to set in as real traffic accumulates. The machine is built; the rhythm around it is still forming.

The checklist I actually walk through, per application:

  1. MRR fit: Are they at $5-50k subscription revenue? Sources: the signup form, LinkedIn, the company website. If I can't verify that, I ask in a reply email instead of guessing.

  2. Engagement: Did they reply to Email 1 or 2 with substance? A one-line "yes please" is borderline. A specific question about their decline codes is a clear pass.

  3. Stripe-using: Is there real evidence they run Stripe? Without evidence/confirmation they stay on the GA waitlist.

  4. Founder availability: Did they confirm 15 minutes for a 1:1 call? This one is really important, because the feedback loop is the whole point of the cohort.

The decision rule: all four pass means approve. One soft fail means a clarifying email, and two fails means soft-reject - they keep their waitlist spot for GA, they just don't get a founding seat.

The non-obvious part, and honestly the one I'd recommend hardest: I write a 2-3 line note on every decision for approvals AND rejections. Future-me needs to remember why row 41 got a clarifying email while row 42 got a seat. Beyond the MRR and churn numbers, I write down whether the operator seems open to actually getting into their product and business with me. If they are up for that kind of conversation, it tips a borderline call, because that openness is the clearest sign they will give me the real, direct feedback this cohort exists for. A real note reads something like: "$14k MRR Stripe SaaS, asked a sharp question about insufficient_funds vs card_declined retries, said yes to a call, clearly up for a deeper product conversation. Approve." Without written reasons, the logic decays into vibes within a few weeks.

What I'm not doing yet: numeric scoring. It's pass/fail per criterion. If approval volume gets uncomfortable, a 1-3 scale per criterion is the fallback, but I'd rather not add machinery before the volume demands it.

Full honesty on where I expect this to break first: the 1:1 call. It takes the most manual time per operator, and it is also the biggest driver of a good relationship, so losing it stings. As volume grows it is the first thing that falls off, but I may keep doing it for operators who are big or interesting enough, and find a lighter path for the rest. The check I call non-negotiable today is the one I will probably have to ration first. And wave-1 invites go out next Monday, June 29. That's this flow's first contact with reality, and I expect edge cases the checklist wasn't designed for. I'll report what breaks.

If you want one of the 30 founding seats, the waitlist is open at recoverstack.dev/early-access: $5-50k MRR Stripe SaaS, free through July 31, then 40% off list for life. Now that you've seen the checklist, a reply with your actual decline-code pain is exactly what moves a flagged row to approve.

If you've run an application-gated beta or cohort, what's the one check you added after launch that you wish you'd had on day one?

Comment

June 15, 2026 Why my founding cohort is hand-curated, not auto-issued

Two weeks from the first cohort invites going out, so it's time to write down a decision I actually made back in early May, before a single person was on the waitlist: RecoverStack's founding cohort is hand-curated. No auto-issued invite codes. I read and approve every application myself.

Who are the founding cohort? They are RecoverStack's first 30 customers, invited starting June 29. They get the real service working on their live Stripe account for free all through July 31. Then, they get 40% off list for life when the first charge fires on August 1. That's the deal, and it's a real one, which is exactly why I care who fills these seats.

The default playbook theory says otherwise: Collect a waitlist, blast codes & count signups. My planning math says that route fills maybe 15 of the 30 seats (300 waitlist x 5% conversion, scenario numbers, not data). And it fills them with whoever clicked first.

The problem is what the cohort is FOR. To me these aren't beta testers, they're design partners on the whole journey of getting this thing off the ground. Their recovery numbers, their onboarding friction, their (permissioned) case studies are what has to carry the August 1 hard-launch. That only works if I pick for fit and earn their trust first, which is hard to do if their invite codes are automatically issued to them.

So every signup goes through three filters by hand. Stated MRR fit: $5-50k subscription revenue. Engagement quality: did they reply to the drip with substance? Founder availability: did they commit to 1:1 interactions?

Here's the honest part: I've never run a cohort before. I'm preparing talking points, but mostly I want the 1:1s to flow naturally and hear the operator's actual problem. Maybe it's something I can build into the product, maybe it isn't and I learn something anyway. Either way I want it first-hand.

A concrete approve-vs-fail: "send me the link" and nothing else is a probably fail. "We're at $12k MRR on Stripe, our biggest decline code is card_declined, can your retry logic tell that apart from insufficient_funds?" is very likely an approve, and honestly that's a person I want on a call.

The cost is real: about 30 minutes of triage per member, 30 members, roughly 15 hours across the curation window. For a solo founder working on many other surfaces that's not a rounding error. A peer told me it doesn't scale. He's right, and it shouldn't. The founding cohort gets special treatment on purpose. Later, with the tone set and hopefully a team beside me, the big-client talks stay 1:1 but the rest gets systematized.

Next Monday I'll show the actual approval flow: the checklist, the admin command, the notes I write on every decision.

If you run a Stripe SaaS in the $5-50k MRR range and want one of the 30 founding seats, the waitlist is open at recoverstack.dev/early-access. Free through July 31, then 40% off list for life. I read every application myself, so a line about your actual decline-code pain goes a long way.

If you've run a founding cohort either way, what did your selection method actually get you?

Comment

June 8, 2026 A 5-minute fix that became a 3-hour debug session

Last Wednesday at 16:55 IDT, Sentry pinged me about a Resend 403 on a welcome email that did not reach its destination. It should have been a 5-minute env-var fix, but it turned into a 3-hour debug session against three different tools, each of which broke in a way I'd never seen.

Tool #1 was the backend coding agent: I asked for a retry script that reads DATABASE_URL from env. The resulting script required setting the envvars temporarily in the terminal, but since I was stressed out I pasted the literal envvars directly in the scripts, which was later committed to Github. Caught the hardcoded prod password 10 minutes after push, so we force-reset the branch and rotated both creds.

Tool #2 was Supabase: I rotated the password 3 times across ~60 minutes, every attempt failed against the Session Pooler with 28P01. Eventually tried the Transaction Pooler at port 6543 with the same credentials, which connected fine. The Session Pooler was probably caching the old auth for ~30 minutes after every reset. Same password, different pool, one fails and one works.

Tool #3 was Chrome: I had a browser agent helping with the rotation clicks, and the design intent was that the password never enters the agent's context: the agent clicks the Supabase "Copy password" button, the clipboard carries the value, and I do the pasting into Railway. However, the clipboard never really updated. Chrome locks clipboard writes behind real user activation, and CDP-driven synthetic clicks don't always satisfy that, so I was pasting stale buffer the whole time.

Every single one of these looked like a normal auth error at the Railway end. The lesson: when 3 different tools all silently fail in a row, extinguish the fires first, then sit down to reflect. Dwelling on placing the blame just slows you down.

Action items I left with: install GitLeaks across all sub-repos, promote pre-push grep verification into the default agent teammate brief, test both Supabase pooler ports before re-rotating, real-mouse click + Notepad-verify for any credential rotation driven through the browser.

Postscript, because the deepest fix only landed yesterday, as I was writing this. A follow-up dev rotation still cost me another ~30 minutes of database downtime: resetting the shared postgres superuser password in place breaks every existing connection at once, and then the pooler cache lag sits on top of that. Now, the app connects through a dedicated least-privilege role instead of the superuser, and rotations are a two-role overlap: create role B with a fresh password, cut the connection string over while role A stays valid, then retire A. And the result? The dry run had zero seconds of downtime. The next rotation should be a non-event, which is the whole point.

What's your heuristic for the moment you stop suspecting yourself and start suspecting the tool?

1 Comment

  1. 1

    My rule is usually: if the same symptom survives three independent explanations, I stop assuming I'm the only variable.

    What stood out more to me, though, is the process change at the end. Most of the post reads like debugging incidents, but the dedicated role + overlap rotation is really a decision about reducing future operational risk, not fixing a one-off outage.

    That's the difference between solving the failure and removing the class of failures.

    Worth separating those two because founders often celebrate the fix and miss the process change that actually matters.

    Happy to put the tighter version in writing if useful. This feels like one of those lessons that's more valuable as an operating principle than a debugging story, and I'd rather not crowd the thread with it.

June 1, 2026 When you can ship but can't invoice

The realization didn't hit me all at once, it built up over a week of small confirmations.

I'd been targeting a soft launch around June 1st, then a hard launch July 1st. About 4 weeks between them, tight but doable. Then Firstbase, the service I'm using to handle my US incorporation and the IRS paperwork, faxed my SS-4 to the IRS and the timeline came back: Day 21 if everything will go smoothly, ~30 business days if you don't have an SSN. After the EIN, another 1-5 business days for the business bank to verify. After that, another 1-4 weeks for Stripe Connect production verification. Suddenly, June 1st wasn't realistic anymore. Realistically - late June, maybe even early July.

Here is the frustrating part: the bottleneck isn't engineering (The retry engine/the cohort onboarding flow/the dashboard/the dunning emails). I probably could ship by June 1st. The real bottleneck is the bureaucracy involved. Without the EIN, the LLC can't open a US bank. Without the bank, Stripe Connect can't go live. Without Stripe Connect verified, the platform can't process a single charge. Nothing I can speed up by working harder.

The first move I considered was holding the July 1st hard launch and absorbing the slip into a 1-2 week soft window, which was reasonable on paper.

Then I thought about what 1-2 weeks would actually mean to me.

The founding cohort phase was supposed a special phase during the launch. Time to onboard customers by hand, watch the engine make its first steps and handle real Stripe failures (not test data), do 1:1 onboarding calls about the good, the bad, and the ugly, write Recovery Reports with actual numbers, gather permissioned testimonials, and (this is the part I usually don't say out loud) build some confidence as a first-time founder before the hard-launch traffic spike.

A 1-2 week soft window doesn't enable any of that. It becomes a sprint to launch, not a learning phase, and the cohort feels like a meaningless checkbox.

So I slipped both: Soft launch June 22-29, hard launch August 1st, with 5-6 weeks between them. Cost: about a month of pre-launch revenue I could have been earning.

There's a freedom in being pre-public for this kind of decision. No waitlist had been told a date, no tweet was pinned, no "launching in July 1st" badge to walk back. Slipping was genuinely free of reputation cost, the only audience I owed an explanation to was myself. I think that's underrated. The pressure to hit a date you announced before you knew what you were committing to is a real reason founders ship cohorts as checkboxes instead of phases. Being a few weeks "behind" with no audience is a much cheaper place to learn than being on time with an audience that wasn't ready for what you actually built.

I might be wrong about needing 5-6 weeks specifically. Either way, I'd rather find that out with a real cohort onboarded than skip the tests entirely pretending 1-2 weeks was enough.

The lesson if you're facing the same call? Being agile and planning accordingly is key to moving forward. Being a stickler to the rules of your plan usually keeps you stuck way too long.

Currently working on the banking applications.

What's the longest you've intentionally delayed a launch, and did the extra time deliver what you hoped?

Comment

May 25, 2026 Three weeks in: three public commitments

Update from the build-in-public side. Three weeks in, three commitments going public.

The reason these are public isn't motivation; it's accountability. Future-me cannot quietly walk them back when every commit, every email, every Monday post is out in the open.

The three:

  1. Every Monday, a diary entry from a real moment. Numbers attached or the post doesn't ship. If nothing real happened in the week, I skip. Manufactured content is the failure mode I'm watching for, not the empty slot.

  2. Monthly Recovery Report once cohort data is in. First one publishes ~7/15, two weeks after soft launch starts (late June). Aggregate cohort recovery numbers, no cherry-picking, breakdown by decline-code category. Designed to be screenshotable for any cohort founder who wants to share their "you recovered $X" digest as a brag without me curating the language.

  3. The personal weekly recovery digest emailed to every paying customer is built to be screenshotable by design. One dominant headline number, clean brand styling. If a founder posts theirs on Twitter, they get the bragging rights, and I get the attribution. Strategic choice baked into the email template from day one.

The ask: if you've made similar public commitments on your own build and one of them quietly drifted, I'd love to hear which one and why. The failure modes are the part I don't have data on yet.

Comment

May 18, 2026 Pre-launch positioning: the 4-position bet I'm making in payment recovery

Update from the build-in-public side.

I spent ~3 weeks mapping the payment-recovery space before writing any marketing copy, and four positions came out of that exercise that no competitor credibly owns more than one of:

  1. Public flat pricing. Churn Buster's entry tier is now $149/mo (MRR-scaled), Churnkey's Starter is $250/mo (annual), Baremetrics Recover is an MRR-scaled add-on inside Baremetrics with its own price tag (~$499/mo at $300k MRR per their calculator). RecoverStack: $49 to $149/mo flat on the landing page, no quote required.

  2. Founder-first. Every competitor is a faceless team or brand. RecoverStack is one human + Claude. My DM is open if anything in the positioning doesn't make sense.

  3. Stripe-specific SEO depth. The long-tail decline-code queries (`stripe insufficient_funds retry`, etc...) are mostly unowned. One pillar page + 5 to 6 cluster posts + 2 to 3 competitor comparisons (8 to 10 pages total) shipping over the next 10 weeks.

  4. Live public metrics. /metrics page goes live on day one of soft launch (~June 22-29). Real numbers in real time, not multi-year aggregates from old customer cohorts.

The structural part is what makes me feel okay about the bet: none of the competitors can take any of these without losing what they already have/who they are. Churn Buster's enterprise pipeline needs sales-call pricing, Churnkey leans on professional-service depth, Baremetrics' MRR-scaled bundle identity can't accommodate flat-priced standalone dunning.

Unit-economics sanity check: 5% to 10% MRR leaks to failed payments across most subscription businesses (Baremetrics ~9% average) x my pricing x 30-seat founding cohort = math that survives if even one of the four runs cleanly.

If you've evaluated Churn Buster / Churnkey / Baremetrics Recover for your own product, which of these four would have been the most decisive filter for you? Drop it below, I'll incorporate the answers into next week's manifesto post.

Comment

About

Bootstrapped Stripe SaaS lose 5-15% MRR to failed payments. RecoverStack is the flat $49-$149/mo alternative with decline-code-aware retries and live public metrics.