SaaS billing in a multi-tenant product is not a monthly cron job that charges every account. It is a ledger of agreements and events: which tenant bought which plan, when access changed, what was invoiced, which payment attempt settled it, and what the product should permit after failure or cancellation. If those concepts are collapsed into a few flags, support and finance will eventually disagree with the application.
This guide explains plans, subscriptions, entitlements, proration, invoices, payment attempts, dunning, and reconciliation as separate but connected parts. It stays provider-neutral because the domain should survive a change in payment rail.
Protect the tenant boundary first
Every billing record must belong to the correct tenant, and every query and authorization check must enforce that boundary. Users may belong to more than one organization with different roles. A billing administrator for one tenant must never see another tenant’s invoice, payment reference, or usage.
Use server-side policies and database constraints, not client-side filtering. Include tenant-isolation tests for invoice downloads, callbacks, exports, support tools, and background jobs. Billing amplifies the impact of a cross-tenant mistake.
Separate the catalog from the commercial agreement
The catalog describes current plans, prices, intervals, currencies, included limits, and available add-ons. A subscription is the tenant’s agreement at a point in time. When the public price changes, an existing subscription may remain on its contracted terms. Do not calculate historical invoices from a mutable plan row.
Store a version or price identifier and snapshot the commercial terms needed to explain each invoice. Decide how taxes, discounts, trials, negotiated prices, and legacy plans are represented. “Plan name” alone is not an auditable agreement.
Make entitlements explicit
Billing answers what was purchased; entitlements answer what the product allows. A plan might include five staff seats, advanced reports, a storage allowance, or access to an integration. Model those grants explicitly rather than scattering plan-name checks throughout the code.
An entitlement service can evaluate the tenant, feature, limit, effective time, and any override. This makes upgrades, trials, support grants, and legacy contracts manageable. It also allows product behavior to remain consistent if marketing renames a plan.
Model the subscription lifecycle
Useful states may include trialing, active, past due, paused, scheduled to cancel, cancelled, and expired, but names should reflect the actual business rules. Define which events enter each state, whether access changes immediately, and whether reactivation preserves the old terms.
Keep effective timestamps for start, current billing period, scheduled changes, cancellation, and end. Avoid a single is_active boolean. It cannot explain a future cancellation or a payment grace period.
Build invoices as immutable financial records
An invoice should contain line items, quantities, unit amounts, discounts, tax treatment, currency, totals, tenant identity, issue time, due time, and references. Once issued, corrections should follow the applicable credit, cancellation, or replacement process rather than silently editing history.
Use decimal minor units or a suitable money representation, never binary floating point for financial calculations. Define rounding at the line and total level, and test boundary cases. Regulatory rules vary, so confirm current invoicing requirements with qualified accounting advice and the relevant authority.
Understand proration before implementing it
Proration allocates value when a subscription changes during a billing period. There is no universally correct formula. A business may credit unused time, charge the new plan immediately, schedule the change for renewal, or disallow mid-period downgrades. Calendar months, fixed-day periods, time zones, and rounding all matter.
Write examples before code: upgrade midway, downgrade scheduled for renewal, seat increase near period end, cancellation during trial, and two changes before the next invoice. Show the expected line items and entitlement timing. Product, finance, and engineering should approve the same examples.
Keep payment attempts separate from invoices
One invoice may have several failed attempts followed by a successful payment, a partial settlement, or a refund. Store each attempt with its provider, amount, currency, status, idempotency key, external reference, and event history. The invoice balance should be derived from valid financial events, not overwritten by the latest callback.
Never trust the user’s return page as proof of payment. Verify server-to-server notifications or query the provider securely, validate amount and reference, and process repeated events idempotently. Our integration service covers these reliability boundaries.
Design webhooks for delay and duplication
Provider events may arrive late, more than once, or out of order. Verify signatures against the raw request, retain the provider event identifier, acknowledge quickly, and process through a durable queue. Make each handler safe to repeat.
If an event refers to an unknown object, quarantine it for review rather than discarding it. Build a replay tool with authorization and audit logging. Read webhooks versus polling for a deeper treatment of retries, ordering, and recovery.
Dunning is a customer workflow
Dunning is the sequence after a payment fails: recording the reason, deciding whether and when to retry, notifying the billing contact, allowing payment details to be corrected, applying a grace policy, and eventually limiting or ending service. It should not surprise the customer.
Classify failures where the provider allows it. A transient network problem is different from a permanently rejected method. Use bounded retries with clear timing, respect provider rules, and stop when a retry cannot help. Keep transactional notices concise and provide a direct account path.
Grace and suspension need product rules
Decide what remains available while an invoice is past due. Immediate lockout may block a customer from exporting data or updating billing details. Unlimited access removes the incentive to resolve the account. A documented grace period and staged restriction can balance continuity and collection.
Preserve read-only or export access where policy requires it, and never delete tenant data merely because a payment attempt failed. Data retention and contract termination are separate decisions.
Reconcile provider money with your ledger
A “paid” callback is not the end of finance. Reconciliation compares internal payments and refunds with provider settlements, fees, reversals, and bank deposits. Store references that let finance trace a line both ways. Surface missing, duplicated, or amount-mismatched items.
Run reconciliation on a schedule and give exceptions an owner. Do not fix mismatches by editing invoice totals. Record an adjustment with a reason and authorization.
Handle usage-based billing deliberately
Define the billable event, unit, source, aggregation window, late-arrival policy, corrections, and tenant visibility. Assign a stable event identifier so retries do not double-count. Preserve raw or auditable aggregates long enough to resolve disputes.
Show customers current usage and the measurement delay. Set alerts before limits where useful. Usage metering is a data product; it needs schema versions, monitoring, and replay plans.
Support needs safe tools
Support staff may need to view a timeline, resend an invoice notice, schedule cancellation, grant a documented extension, or replay a failed event. Tools should use constrained actions with reasons and audit logs. Direct database edits make later reconciliation almost impossible.
Present one chronological view across subscription changes, invoices, attempts, provider events, notices, and entitlement changes. A timeline often resolves a case faster than separate admin screens.
Test time and money as first-class inputs
Use a controllable clock in tests. Cover month boundaries, leap years, time zones, daylight changes where relevant, trial expiry, delayed events, duplicate callbacks, partial refunds, and scheduled plan changes. Use property or table-driven tests for money and proration examples.
Test tenant isolation and authorization around every admin action. Run contract tests against provider sandboxes, but keep deterministic local tests for your own state machine.
Migrate billing without rewriting history
When moving from another system, import customers, active agreement terms, current periods, outstanding invoices, credits, and provider references. Decide which system owns renewals during the cutover. Reconcile a sample and totals before enabling new charges.
Keep a mapping between old and new identifiers. Never trigger a fresh payment merely because a record was imported. Plan rollback around the point at which the new system starts issuing financial events.
A billing architecture that can grow
A practical design has a catalog, subscription service, entitlement evaluator, invoice ledger, payment-attempt store, provider adapters, event inbox, dunning workflow, and reconciliation process. They may live in one modular application; they do not need separate microservices to have clear responsibilities.
Our SaaS development service builds these boundaries into the product, while custom software versus SaaS helps decide whether building billing is justified at all.
Closing the ledger
The test of multi-tenant billing is not whether the first monthly charge succeeds. It is whether a support agent can explain an upgrade, a duplicate event, a failed retry, a credit, and current access from one auditable timeline. Start by writing lifecycle and proration examples with finance, then scope the billing workflow before choosing provider APIs or UI components.


