Last time, in Accepting Payments with Stripe, I covered the part everyone assumes is the hard bit: taking a card and moving money. It isn't, really. Stripe does the hard part. The hard part starts the moment that first payment succeeds and you have to answer a much less glamorous question: what plan is this customer on, what does that plan let them do, and how do you keep that answer correct for months or years without anyone watching it by hand.
This is part of the Full Stack SaaS Masterclass, the series where I build a multi-tenant SaaS from an empty repo forward. Payments got you a charge. Billing is the system that turns a charge into an ongoing, changeable, cancellable relationship, and it's where a surprising number of SaaS products quietly rot: seats that don't reconcile, plans that grant access a card no longer backs, downgrades that never take effect.
None of this is exotic engineering. It's mostly state management done carefully, plus a habit of never trusting the client to tell you what it paid for.
Billing is a state machine
The instinct when you're new to this is to treat a subscription as a boolean: paid or not paid. It doesn't hold up. A real subscription moves through states like trialing, active, past_due, unpaid, canceled, and incomplete, and each one has different implications for what a user should be allowed to do. A past_due customer whose card just expired shouldn't be locked out immediately. That's how you lose someone over a routine card reissue. But they also shouldn't keep provisioning new seats indefinitely while unpaid.






