SaaS subscription billing works reliably when recurring charges, invoices, and product access agree throughout the customer's lifecycle. Model a paid period, its renewal, and its end explicitly. A checkout success page alone is not evidence that an account should retain access forever.
This guide walks through a fictional $20 monthly subscription, then adds failed payments, plan changes, cancellation, refunds, and event-delivery failures. The tables are an application-design example, not universal provider status names. Stripe, Paddle, and Lemon Squeezy documentation was checked on October 14, 2026; no live billing integration or transaction was tested.
Define the records before writing the workflow
Separate the commercial agreement from the individual payment. A subscription describes recurring terms; an invoice records an amount due; a payment records an attempt or outcome; an entitlement defines what the account may use. Those records answer different questions.
For example, a customer may cancel future renewals while still having access through an already-paid period. A payment can fail while the application grants a deliberate short grace period. Neither situation is represented well by one is_paid flag.
| Record | Question it should answer |
|---|---|
| Internal account | Which person or organization receives access? |
| Provider customer | Which external customer record belongs to that account? |
| Subscription | What renews, at which interval and effective dates? |
| Invoice and payment | What was owed, attempted, collected, or adjusted? |
| Entitlement | Which product capabilities are allowed, and until when? |
| Processed event | Which incoming notification has already been handled? |
Preserve provider IDs alongside stable internal IDs. Do not rely on an email address as the only join key: customers can change addresses, organizations can share billing contacts, and a buyer may manage several workspaces. Decide which workspace owns the purchase before starting checkout.
Walk through one monthly subscription
Our example product has a $20 monthly plan and no usage charges. The example excludes tax, discounts, currency changes, and proration so the sequence stays readable. It is a proposed operating policy, not a provider's default.
- The signed-in customer chooses the plan for a specific workspace.
- The server creates the supported checkout flow using the intended price and account association.
- The customer completes the provider's payment flow.
- The server receives and verifies the relevant provider notification.
- The application confirms the current subscription and payment facts, then grants the purchased access period.
- A later renewal extends access after the configured confirmation conditions are met.
- A cancellation stops future renewal at the intended time, with access ending according to policy.
A closed browser tab must not prevent step five. Conversely, a browser returning to a success URL must not manufacture payment confirmation. The entitlement update belongs to a trusted server-side workflow.
Design a subscription state and access table
Use your own clear application states and document how provider facts map to them. The following names are illustrative; do not send them to an API unless its documentation defines them.
| Application situation | Example customer experience | Access decision |
|---|---|---|
| Checkout not confirmed | Purchase still pending | Do not grant paid access yet |
| Trial within its allowed period | Trial features and end date are visible | Grant only the specified trial entitlement |
| Confirmed paid period | Paid plan is active | Grant the purchased features through the confirmed period |
| Renewal payment failed | Explain the issue and payment-update route | Apply an explicit grace or restriction policy |
| Cancellation scheduled | Show the renewal stop and access-end dates | Preserve access through the intended paid period |
| Paid period ended without continuation | Show how to resubscribe or export data | End paid entitlements according to policy |
| Refund or dispute needs review | Provide a clear support route | Apply the separately defined adjustment policy |
Stripe's subscription overview describes its own lifecycle. Paddle's access-provisioning guide explains how its subscription states can inform access. Review the exact semantics instead of copying status strings between vendors.
Do not assume a provider's “active” label means every relevant invoice is paid. The facts needed for access depend on the pricing model and the provider's documented behavior. Store the effective dates and the reason for an entitlement decision so support can explain it later.
Handle failed renewal without inventing a grace period
A failed renewal creates a product decision as well as a collection problem. Decide how long, if at all, to retain access, whether the account can export its data, and where the customer updates payment information. Publish behavior that matches the implementation.
For our fictional product, suppose the business chooses three days of temporary access after a failed renewal. That is an example policy, not a recommendation for every product or a vendor default. Record when that period begins, what ends it, and what happens if payment succeeds during it.
Document these cases:
- A retry succeeds before the grace period ends.
- Every configured retry fails.
- A customer updates their payment method but payment is not yet confirmed.
- The customer cancels while recovery is in progress.
- A previously delayed success notification arrives after a restriction job ran.
Stripe's subscription webhook guide describes relevant notifications. Lemon Squeezy's subscription documentation describes its recovery and subscription behavior. Provider retry configuration and your entitlement policy must be coordinated; neither should be inferred from the other.
Make plan changes explicit before calculating money
An upgrade can change features immediately, at the next renewal, or only after a confirmed additional payment. A downgrade can take effect immediately or after the current period. Each option changes what the customer expects and what the application must enforce.
Write three separate decisions for every change: effective time, billing adjustment, and entitlement change. A credit on an invoice is not automatically a cash refund, and an additional charge attempt is not automatically a successful upgrade.
For illustration, a business could choose to schedule a move from a $20 plan to a $10 plan at the next renewal. In that policy, the old features continue through the current period, and the new price and features begin together later. The example deliberately avoids a mid-period credit calculation.
For immediate changes, preview the adjustment using the provider's supported flow. Stripe's proration documentation explains conditions that affect its calculations. Do not calculate “half the month” on the client and assume it matches the provider's billing timestamps, settings, and invoice behavior.
Separate cancellation, expiration, and refund
Cancellation answers whether future renewal continues. Expiration answers whether the current access period has ended. A refund changes the financial record. They can interact, but they are not interchangeable actions.
Stripe's cancellation documentation distinguishes cancellation options. Whichever provider you use, present the customer's effective cancellation date and the consequences for access before they confirm the action.
| Request | Questions to settle |
|---|---|
| Stop renewal after this period | What is the last access date, and can the decision be reversed beforehand? |
| End immediately | What happens to unused time, data access, and outstanding charges? |
| Refund one payment | Does the recurring agreement continue, and what access adjustment follows? |
| Change annual to monthly | When does the new interval begin, and how is any adjustment handled? |
Give support staff a procedure that refers to the payment, subscription, and entitlement separately. A single “refund” button should not be assumed to implement every part of the customer's request. Confirm the result against the provider record and the product account.
Treat webhook delivery as a reliability boundary
A webhook is a server-to-server notification. It is not a guarantee that every notification arrives once, in the order your business story happened. Stripe's webhook documentation describes verification, retry, and ordering considerations; Paddle documents signature verification.
A robust design should:
- Verify the provider signature against the original request as required by its SDK.
- Persist a stable event identity so repeated delivery is safe.
- Map the event to the correct internal account and subscription.
- Retrieve current provider state when an older notification could cause a regression.
- Apply the entitlement transition and its audit record consistently.
- Acknowledge delivery after the work has been durably accepted, then process safely according to the integration's design.
Design crash behavior deliberately. If the service updates access and crashes before recording the event, a retry must not grant duplicate credits. If it records the event but crashes before access changes, a duplicate check must not permanently skip unfinished work. A durable processing record and an atomic or recoverable transition are more useful than a bare “seen IDs” list.
Maintain a reconciliation job or review process for unresolved discrepancies. Webhooks are the fast path; reconciliation gives the business a way to detect missing or inconsistent updates. The exact schedule should follow the product's risk and operating needs.
Test behavior that can cost customers money or access
Build an acceptance matrix before enabling live billing. Use supported sandbox tools and provider-documented test scenarios, not fabricated production payment events.
| Scenario | Expected evidence |
|---|---|
| Buyer closes the tab after paying | Confirmed server-side state still grants the correct access |
| Initial payment remains incomplete | No unintended permanent paid entitlement |
| Same event arrives twice | One effective entitlement or credit change |
| Old event arrives after a newer update | Access does not regress to an obsolete state |
| Renewal fails, then succeeds | Recovery and access dates match the chosen policy |
| Cancellation is scheduled | Paid access lasts until the intended end |
| Refund affects an active subscription | Financial and access outcomes are both recorded |
| Worker crashes partway through processing | Retry finishes safely without losing or duplicating work |
For each row, save the account ID, provider references, expected dates, actual result, and owner. A test that only checks whether an HTTP response is 200 does not establish that the customer received the correct product.
Reconcile the subscription operation after launch
A weekly review can start with a small list of mismatches: paid invoice without expected access, access without a valid supporting period or grace policy, canceled subscription still scheduled for unintended renewal, and unresolved refund adjustments. Review evidence rather than deleting mismatches to make the dashboard look tidy.
Track events that help diagnose behavior: payment attempt outcomes, recovery after failure, cancellation effective dates, entitlement transitions, and payout reconciliation. Revenue, cash received, and product usage are different measurements. Keep them separate when deciding whether the website is becoming sustainable.
Assign a support owner for the first paid customers. Give that person enough record mapping to answer “I paid but cannot use it” without asking the customer to send card details. Use the provider's secure tools for payment-method updates rather than collecting sensitive information in ordinary messages.
Keep the billing model small enough to explain
Start with pricing and lifecycle rules your team can describe unambiguously. Add usage meters, complex seats, or custom invoice terms when a real requirement justifies their operational cost. Complexity does not disappear because a billing provider exposes an API for it.
Use the payment-gateway selection guide to choose the selling setup, and the Stripe vs Paddle comparison to examine that specific responsibility choice. A customer-success workflow can help assign the support handoffs after signup.
The practical deliverable is a state table, a set of effective dates, a reliable event-processing design, and an acceptance matrix. With those in place, SaaS subscription billing becomes a process the team can operate and explain, not just a recurring charge attached to a checkout button.
Define the commercial rules before configuring billing: compare B2B SaaS pricing models for quantities and overage, then use freemium versus free trial to specify temporary access, the paid boundary, and what happens to saved work.


