The Stripe quickstart gets you to "a customer can subscribe" in an afternoon. Card form, Checkout session, a customer.subscription.created webhook, a row in your database. It feels finished. It is about 30% finished. The subscription billing edge cases that make up the other 70% — proration on a mid-cycle plan change, a renewal charge that silently fails, a cancellation that should leave access intact until the period ends — none of those are in the quickstart, and every one of them shows up in production.

I've built and maintained this layer on real recurring-revenue systems, and the lesson that took longest to fully internalize is uncomfortable: subscription billing is a state machine you don't own. Stripe owns the truth. Your job is to faithfully mirror its state, not to compute billing reality yourself. The teams that get burned are the ones who treated billing as a feature they finished rather than a system they maintain.

This article is the messy middle. It assumes you already have basic Stripe subscriptions working and you're now hitting the hard cases. It is not a "how to integrate Checkout" tutorial. It is the list of things that break after launch, why each one is subtle, and how I actually handle it.