Metering AI credits without billing disputes
Jun 14, 2026
Most AI products bolt usage tracking on as an afterthought: a counter column that some background job increments and hopes nobody disputes. It works until the first customer asks "why was I charged for that?" — and you have no answer.
The counter trap
A single credits integer that you SET from a value computed in application
code has three failure modes:
- Concurrent generations race and overwrite each other.
- A crash mid-charge leaves the balance and the work out of sync.
- There is no history, so a dispute is your word against the customer's.
Money and credits are ledgered, never mutated blindly.
A double-entry ledger
Every movement is an append-only credit_transaction row. The cached balance is
only ever changed by a guarded statement:
UPDATE "user" SET credits = credits - $1
WHERE id = $2 AND credits >= $1
RETURNING credits;
If the row comes back, the charge succeeded atomically. If it doesn't, the user was out of credits and nothing happened — no partial state to reconcile.
What the customer sees
- Every generation, with the model and the exact tokens it consumed.
- A running balance they can audit line by line.
- Top-ups and monthly grants as their own entries.
When the next "why was I charged?" arrives, you send a link to the ledger and the conversation is over. See the pricing page for how credits map to plans.
Metering is not glamorous, but it is the difference between a product people trust with their card and one they don't.