Building in PublicMarch 21, 2026

I Spent 300 Hours Building a SaaS Payment System So Nothing Goes Wrong

From breaking down at test case #16 to covering 30+ payment edge cases over 300 hours. Code isn't the hard part — making sure it's correct is, especially when money is involved.

01

One afternoon in late February, I was testing the subscription pricing logic — picking up where I'd left off the day before. Finish a scenario, check it off, move on to the next.

That day I finished #16. Out of habit, I scrolled down to see what was left.

30+ more, waiting in line.

I let out a long sigh, stared blankly, and just sat there.

It wasn't exhaustion. It wasn't wanting to quit.

It was a very specific feeling — I thought I was almost done, but the bottom wasn't where I thought it was. Every test case doesn't just end when it passes — it can surface new problems.

It's hard to describe. Not despair — something quieter. Like thinking you've reached the end of a road, only to find a bend, and another road stretching out beyond it.

For the next few days, I ate meals without tasting anything. My head was foggy.

At night, lying in bed, my brain kept running through scenarios — did I test this one? Did I cover that edge case? Will credits get double-deducted under concurrency? After a downgrade, is the next billing cycle amount correct? Get it wrong, and you lose more than users and revenue — you lose trust...

Even when I fell asleep, I was still testing in my dreams.

02

Later I thought about what this anxiety really was.

Code running without errors doesn't mean it's correct.

The hardest part of payments isn't the logic itself — it's the sheer number of edge cases. So many that you don't know what you don't know.

  • Out-of-order webhooks. A user successfully renews, but the subscription expiration webhook arrives a few seconds late, overwriting the just-renewed subscription as expired.

  • Downgrade then upgrade. A user downgrades but it hasn't taken effect yet. Then they upgrade. The system doesn't clear the pending downgrade, and at the end of the period, it downgrades the just-upgraded plan back down.

  • Lazy expiration gap. Creem or PayPal's expiration webhook never arrives. The subscription expired ages ago, but the system still shows "active" — two free weeks.

Every time I hit one of these, the same thought crept in: how many more are there that I don't know about?

There's no answer to that question. You can't enumerate every possibility. But after launch, your users will find them for you.

And when that happens, you won't be there. You'll be having dinner with family, resting, traveling. The code is running. Users are paying — or paying and finding something wrong, and coming to you.

Just thinking about that feeling... I don't want to live through it.

03

So I did it myself. Over 300 hours, I got it done.

All that time wasn't spent writing code — the actual coding took just a few days.

80% of those 300 hours went to testing. Thinking about what scenarios weren't covered yet. Constructing edge cases. Running them. Fixing. Running again. Checking the subscription table, the credits table, the payment provider's subscription status, the frontend display. I must have repeated these steps hundreds of times. But miss even one, and it's a ticking time bomb.

Marc Lou, one of the iconic figures in the indie dev community, posted a tweet recently.

The first time I saw that, it resonated deeply.

Yeah — in an era where AI can write code for everyone, writing code is no longer a moat.

Ruanyifeng also published a post recently: in the age of AI, testing is the new moat. An engineer spent $1,100 and one week recreating Next.js. Code is no longer the moat — test cases are.

It's true. Code isn't hard. What's hard is making sure it's correct — especially when money is involved. Get it wrong, and either your users lose or you lose.

"It runs" and "it runs correctly, reliably, without causing anyone trouble" are two very different things. How do you guarantee correctness? Only through extensive testing. There's no shortcut.

Code is genuinely easy now. AI can generate it, autocomplete it, refactor it. But AI doesn't know where your business logic will break, how users will actually behave, or what happens under concurrency.

AI generates the code. But when things go wrong — disappointed users, complaints, churn — that's our mess to clean up.

Testing is our job. No one can do it for us — unless someone has already done it once and left the results behind.

04

Because I worried about all of this, I built Pay4SaaS. It covers 30+ edge cases — not a feature checklist, but real pitfalls I either hit or anticipated and then verified. Every webhook is handled, every race condition is covered. For example:

  1. Trial abuse prevention — an account that already used a trial won't trigger trial logic again on a paid subscription. I even wrote a dedicated post about this one.

  2. Concurrent deduction — multiple requests consuming credits at the same time, no over-deduction, no under-deduction.

  3. Prorated upgrade/downgrade — upgrades charge the difference immediately, downgrades keep current access until the period ends, then switch.

  4. Webhook idempotency — the same event firing multiple times won't cause duplicate database writes.

  5. Credits floor protection — when balance is low and concurrent requests hit, insufficient balance gets rejected. Credits never go negative.

  6. Out-of-order webhook guard — a late-arriving expiration webhook won't overwrite an already-renewed subscription.

  7. Lazy expiration self-healing — every access automatically detects and fixes subscriptions that expired but weren't marked as such.

Every scenario has a corresponding test case. What you're buying isn't code — it's the certainty and peace of mind that comes from someone having walked through every one of these pitfalls already.

05

I built this for developers who are serious about monetizing their SaaS with subscriptions. Not dabblers — people who want to get payments right and keep them right for the long run.

The best part of being an indie developer is freedom. Freedom of time, freedom of income. No reports, no meetings. Ship your code, go to sleep, wake up to payment notifications. But all of that depends on one thing: the payment system itself is correct and reliable. Without that, everything else is just talk.

If you're on this path too, and you've felt that nagging "how many more pitfalls are out there" feeling —

$199, pay4saas.com. A SaaS monetization infrastructure that lets you charge with confidence. Take a look and see if it fits. Prices will increase over time — this is the lowest it'll be.