Tensor LabsTENSORLABS

Bill from a ledger, not a counter

Usage you can replay is revenue you can defend

July 6, 20263 min read3 sectionsBy Ahmed Abdullah
Bill from a ledger, not a counter

Introduction

The invoice said $4,318. The customer's own dashboard, built from the same product's usage screen, said $3,120. Both numbers wore the company's logo, and the email from the customer's CFO quoting them side by side was three sentences long, which is somehow always worse than a long one.

The support thread that followed consumed a solutions engineer for most of a week, ended in a goodwill credit, and never actually established which number was right. That last part is the detail worth dwelling on. The company did not lose the argument; it discovered it had no way to have the argument, because usage was being counted rather than recorded.

Under the hood sat the pattern that produces almost every billing dispute in usage-priced software: a counter. Somewhere in the application, an API call or a job completion incremented a number in a row, and that number eventually became money. The increment lived inside a retry loop, so a transient timeout could count one API call twice. A deploy mid-month had dropped a few minutes of events, uncounted and unknowable. The counter held no history, only a total, so when the total was challenged there was nothing underneath it to inspect.

(The increment was inside the retry handler. Of course it was.)

An invoice is a claim. A ledger is the evidence.

Metering is infrastructure, not a variable

The fix treats usage the way banks treat transactions: every billable event is a record, immutable and identified, in an append-only usage ledger, and every number on an invoice is a query over those records that can be rerun by anyone at any time.

Three mechanisms make it defensible. First, idempotent ingestion: every event carries a unique ID at the point of origin, and the pipeline deduplicates on it, so at-least-once delivery, the retry-happy reality of Kafka and every webhook system ever built, cannot double-charge anyone. Second, watermark-based aggregation: events arrive late, so the meter closes a billing window only when it is confident the stragglers are in, and any event arriving after the close lands in an adjustment line instead of silently mutating a total that finance already exported. Third, reconciliation: a scheduled job re-derives every invoiced aggregate from the raw ledger and alarms on any drift between what was computed and what was billed, which turns "a customer noticed" into "a cron job noticed," several weeks earlier and with no goodwill credit attached.

None of this needs inventing. OpenMeter and Lago are open-source and implement the ledger-and-watermark pattern out of the box; Stripe Billing and Metronome will consume clean meter reads and handle the invoicing arithmetic. The engineering decision is not which tool. It is whether usage data deserves the same care as the money it becomes, and the counter answers that question wrongly by construction.

If you cannot replay the month, you cannot defend the invoice.

The revenue nobody has to argue about

The commercial effects run deeper than fewer angry threads. Usage-priced deals with real contract values now come with procurement teams who audit; "here is the event-level ledger behind your invoice, query it yourself" ends those conversations before they start. Finance gets revenue recognition built on records instead of a mutable integer. And the product team gets to price new things confidently, because launching a new billable metric is adding a query, not instrumenting a new counter and praying.

We rebuilt metering for a SaaS platform that was writing off about 2 percent of revenue a year in disputes it could not win for lack of evidence. The ledger did not just stop the write-offs; it surfaced a class of events that had never been counted at all, which paid for the project on its own.

At TensorLabs we build the unglamorous layers, metering, ledgers, reconciliation, that make the glamorous ones billable. If your usage numbers come from counters, the gap between claim and evidence is already on your books. You just have not been sent the three-sentence email yet.