Production Readiness

The Checkout Worked. Then the Billing State Drifted.

The checkout can look healthy while Stripe and your product disagree about who has paid and what they should be allowed to use.

A successful checkout surface hides mismatched payment, subscription and customer-access states behind it.
A successful checkout surface hides mismatched payment, subscription and customer-access states behind it.
A successful checkout surface hides mismatched payment, subscription and customer-access states behind it.

The demo moment is satisfying: choose a plan, enter a test card, land on the success page, see the account become Pro.

Payments are done.

Except that is usually the moment payments start becoming a production problem.

The first payment is the easiest payment

Your first successful checkout follows the path you designed. Real customers introduce the paths you did not rehearse.

Someone's renewal fails. Someone cancels from Stripe. A webhook is retried. An event arrives later than expected. Your database has a bad minute. A customer pays successfully but your app never activates them. Or the reverse: Stripe stops billing them while your product keeps granting paid access.

None of those failures need to make the checkout page look broken.

That is what makes billing drift uncomfortable. The customer-facing surface can look healthy while the product and the payment provider disagree about who has paid for what.

'Stripe says delivered' is not the same as 'the customer got the right outcome'

A webhook is just a message arriving at your application. Your product still has to decide whether to trust it, whether it has seen it before, and what state should change because of it.

Current Stripe guidance explicitly says webhook signatures should always be verified. Fresh 2026 builder discussions go further: people are still talking about duplicate delivery, stale subscription state and the cost of verifying AI-generated integration code after the happy path already works.

One May community probe reported that 1,542 of 6,000 probed webhook endpoints returned 200 to a fake Stripe-style event without a signature header. That result should not be treated as a market-wide vulnerability rate, and a 200 does not prove every endpoint granted access. But it is a useful reminder: an endpoint appearing to 'work' tells you very little about whether the business workflow behind it is safe.

The moment the MVP changed

Before customers pay, a billing bug is a development task.

After customers pay, the same bug becomes a trust problem.

A duplicate credit can cost money. A missed cancellation can create an angry former customer. A paid customer without access creates a support ticket at exactly the moment they are deciding whether your product is worth keeping.

This is one of the quiet transitions from MVP to product: the software is no longer allowed to be approximately right about money.

What founders should ask before calling payments 'done'

You do not need to become a payments engineer. You do need answers to a few questions:

  • If Stripe sends the same event twice, do we grant the benefit twice?
  • If a renewal fails, what happens to access?
  • If someone cancels in Stripe, how does the app learn about it?
  • If Stripe says paid but our database update fails, how do we recover?
  • Can an arbitrary internet request pretend to be a payment event?
  • How would we discover that Stripe and our database disagree?

If nobody can answer those, the checkout may be complete while the billing system is not.

Sources

What's next for you?

If your app already takes real money, do one exercise this week: compare what Stripe believes about a handful of customers with what your product believes. Any unexplained difference is a Production Gap worth understanding.