A SaaS credit ledger is the accounting-grade bridge between a commercial promise and a usage invoice. It must explain which commitment funded each charge, why a balance expired, whether a promotional grant was eligible, and when consumption became overage. A mutable balance field cannot answer those questions after retries, corrections, backdated events, plan changes, or disputes. The durable design records immutable entries and derives balances from them.
This ledger is a billing subledger, not the general ledger and not the usage meter. Usage evidence establishes quantity; pricing turns quantity into a charge basis; the credit ledger applies eligible value; invoicing presents the result; and finance determines revenue recognition. Keeping those responsibilities distinct makes reconciliation possible while still allowing a customer-facing balance to update quickly.
Define the credit contract before the schema
Start with the signed order form and product rules. For every grant, define currency or unit, funded versus promotional origin, eligible products and meters, effective interval, expiry policy, allocation priority, transferability, refund treatment, and whether unused value is forfeited or carried forward. Stripe's billing credits documentation similarly scopes credit grants to eligible metered subscription items and associates them with currency. Your internal model may support broader contracts, but it must not imply rights the agreement did not create.
| Contract term | Ledger representation | Decision it controls | Failure if omitted |
|---|---|---|---|
| Committed value | Grant entry with original amount and commercial reference | Maximum funded balance | Sales order and system balance diverge |
| Eligibility | Versioned product, meter, and dimension predicate | Which rated charges may consume a grant | Credits fund an excluded service |
| Effective and expiry times | Explicit instants plus business timezone rule | When allocation can occur | Boundary usage is disputed |
| Priority | Deterministic allocation policy version | Which grant is consumed first | Runs produce different balances |
| Overage terms | Price reference and threshold behavior | Uncovered charge treatment | Invoice exceeds the expected commitment |
| Adjustment authority | Reason code, approver, and source document | Who may correct value | Support edits destroy auditability |
Choose whether credits represent money, product units, or both. Currency credits are flexible but depend on a stable rated monetary amount. Unit credits preserve a product promise such as one million tokens but become difficult when model, region, or quality tiers have different prices. A practical design stores the contractual denomination on the grant and the rating facts on each consumption allocation. Never silently convert between denominations; record a conversion entry with rate source, precision, and rounding rule.
Separate metering, rating, allocation, and invoicing
Meter events need a stable event identifier, tenant, meter, quantity, occurrence time, received time, and dimensions used by pricing. Stripe documents meter aggregation methods such as sum, count, and last, and notes that meter configuration becomes effectively fixed after creation in meter configuration guidance. Treat a meter definition as versioned commercial infrastructure. Changing aggregation semantics in place can reinterpret old evidence.
The rating engine converts a bounded set of meter evidence into rated charge lines. Each line should retain meter version, price version, quantity, tier calculation, currency, tax classification inputs, period, and rounding remainder. The allocator then matches a rated line against eligible grants. It creates allocation entries; it does not rewrite the rated line. The invoice composer groups uncovered amount as overage and covered amount as credit application, preserving links from every displayed line back to rating and allocation evidence.
Model append-only entries and derived balances
| Entry type | Value effect | Required references | Typical trigger |
|---|---|---|---|
| grant | Increases available value | Contract, order, currency or unit, eligibility version | Prepayment received or promotion approved |
| reservation | Temporarily reduces spendable value | Rated estimate, expiry, idempotency key | Long-running billable operation begins |
| release | Restores reserved value | Reservation entry and reason | Operation cancels or settles below estimate |
| allocation | Consumes available value | Rated charge line and grant | Billing period closes or near-real-time charge settles |
| expiry | Removes remaining eligible value | Grant and contractual expiry rule | Expiry instant passes |
| adjustment | Increases or decreases value | Original entry, reason, approval, case | Correction, credit note, or dispute resolution |
| transfer | Moves value through paired entries | Source, destination, authorization | Contract permits account reorganization |
Every entry needs an immutable ID, account, grant where applicable, signed amount, denomination, effective time, recorded time, source type and ID, policy version, idempotency key, actor, and integrity metadata. Corrections are reversing and replacement entries. A balance projection groups posted entries by account and grant; it can be rebuilt and compared with stored checkpoints. Use database constraints to prevent a source event from posting twice and a transaction to commit the entry with its outbox notification.
Reservations are optional but useful when a single operation could exceed the remaining commitment. They reduce spendable balance without pretending usage is final. Give reservations a deadline and state transition; release them when abandoned, then allocate the actual charge. Without expiry and reconciliation, reservations become stranded value. For high-volume micro-usage, reserve at a bounded workload or session level rather than writing a financial entry for every token.
Apply credits with a deterministic allocation order
Write allocation as a pure, replayable policy over a defined snapshot. First select grants active at the charge occurrence or contractually defined rating time. Filter by account, denomination, product, meter, dimensions, and exclusions. Sort eligible grants by explicit commercial priority, then earliest expiry, effective time, and immutable grant ID. Consume until the rated amount is covered or balances are exhausted. Persist the policy version and candidate set watermark so a replay can explain the same choice.
- Freeze the billable period and identify complete meter evidence at a published watermark.
- Rate usage with the price and aggregation versions effective for each charge interval.
- Select eligible grants and calculate balances from posted entries through the allocation cutoff.
- Create allocation entries in one transaction, rejecting duplicate rated-line idempotency keys.
- Classify the uncovered remainder as overage using the applicable contract price.
- Reconcile ledger totals to invoice lines before finalization and publish customer evidence.
Late usage requires a policy, not an improvised edit. If evidence arrives before invoice finalization, include it and advance the watermark. After finalization, post it to the next invoice or issue an adjustment according to contract and billing policy. Stripe notes that meter summaries update asynchronously and supports unique event identifiers in its usage-based billing model. Your close process therefore needs a lateness window and an explicit answer for events beyond it.
Handle expiry, overage, and adjustments without rewriting history
Expiry should be a posted entry generated once from a grant's remaining balance at its contractual cutoff. Define whether usage occurring before expiry but rated afterward remains eligible. Usually occurrence time is fairer, but the agreement controls. Delay the expiry job until the accepted event-lateness window closes, or allow a controlled reversal when qualifying late evidence arrives. Show expired amount and date to customers before and after the event.
Overage is simply rated value not covered by an eligible commitment, but its invoice consequences can be significant. Provide threshold alerts based on projected exhaustion, not only a zero balance after the fact. Distinguish informational estimates from finalized amounts and disclose processing lag. When a disputed event is canceled, reverse its allocation, restore the original grant if still contractually valid, and create the proper invoice adjustment. Do not deposit value into whichever grant is currently open.
Reconcile the ledger as a controlled financial system
Run invariant checks continuously: posted grants minus allocations, expiries, transfers, and negative adjustments must equal the derived balance; allocations cannot exceed a rated charge; paired transfers must net to zero by denomination; and invoice credit applications must equal linked ledger allocations. Reconcile by account, period, currency, meter, and price version. Investigate differences through source IDs rather than manually forcing totals to agree.
Finance must assess accounting treatment. IFRS 15's core principle is to recognize revenue to depict transfer of promised goods or services in the consideration expected, and its model identifies contracts, performance obligations, transaction price, allocation, and recognition. The IFRS 15 overview does not prescribe your SaaS table design. It does mean engineering should retain contract lineage, service-delivery evidence, expiry, refunds, and adjustments so qualified accountants can apply the policy.
Key takeaways
- Treat balances as rebuildable projections over immutable entries, never as the sole record.
- Keep meter evidence, rating, credit allocation, invoicing, and financial accounting distinct but linked.
- Version eligibility, priority, price, aggregation, rounding, and lateness policies.
- Use deterministic allocation and idempotent posting so retries and replays cannot change economic outcomes.
- Make expiry, late usage, overage, and corrections visible to customers before they become invoice disputes.
- Reconcile business invariants and source links before finalizing an invoice.
SaaS credit ledger FAQ
Is a credit ledger the same as a wallet?
Not necessarily. A wallet often represents transferable stored value and can trigger payments regulation. A contractual SaaS credit may only offset eligible service charges, may expire, and may be nonrefundable. Product language and system capabilities should match legal and accounting analysis; do not add cash-like transfer or withdrawal behavior casually.
Must the ledger prevent a negative balance?
A grant balance should not become negative through allocation. The account can still have uncovered rated usage that becomes overage. Enforce allocation limits transactionally or through reservations, and store overage separately. If the contract allows a credit line, model that entitlement explicitly instead of overloading a prepaid grant.
What should customers see?
Show original grant, remaining amount, denomination, eligibility summary, effective and expiry dates, pending usage caveat, allocations by invoice or usage period, adjustments with readable reasons, and projected exhaustion. Keep internal fraud signals and sensitive operator notes out of the customer view while preserving them in controlled audit records.
Conclusion
A dependable prepaid model comes from explicit commercial semantics and reversible, linked evidence. When the SaaS credit ledger can replay allocation, show exactly why usage became overage, and reconcile to the invoice without manual balance edits, commitments become a product capability rather than a recurring billing exception.