Solutions / Usage-based billing

If you meter it, the invoice has to match.

Usage events flow through queues, aggregation jobs and a billing provider. Each hop can drop, double or delay events, and the customer only finds out when the invoice looks wrong. Invarly checks that what you meter is what you charge.

API productsInfrastructureAI productsCredits and prepaid

Why billing breaks quietly

Usage-based pricing turns every request into money. Events are produced in one service, queued, aggregated in batches, priced, and pushed to a billing system. Each step is retried, scaled and redeployed independently.

A lost or doubled batch doesn’t raise an error. It changes a number on an invoice that nobody checks until the customer does.

Five places it breaks

Events counted twice

A queue redelivers a batch after a consumer restart, and the aggregation job counts it again.

rulecount(usage_event by event_id) == 1

Invoices that don’t match usage

A price change, a new tier, or a timezone bug, and the invoice line no longer equals metered usage times price.

ruleinvoice.amount == sum(usage × price)

Credits going negative

Prepaid credits are checked asynchronously, so usage keeps flowing after the balance hits zero.

ruleaccount.credits >= 0

Usage outside the subscription period

Events are attributed to the wrong period after a plan change mid-cycle.

ruleusage.period within subscription.period

Free tier never ends

A trial flag is cleared in one table but usage limits read another.

ruletrial.ended ⇒ limits = plan.limits

A walkthrough

Composite example, combined from common metering bugs.

A team moves usage aggregation to batches to cut costs. After a consumer restart, one batch is processed twice.

warehouse · usage_dailylive
accountmeteredinvoicedΔ
88256821.00821.000.00
88258496.00496.000.00
88260742.001,484.00+742.00
88263122.00244.00+122.00
88264716.00716.000.00
88265378.00378.000.00
88267449.00898.00+449.00
8827053.00106.00+53.00
88273599.001,198.00+599.00
invoice-matches-usage≠ open
rule invoice.amount == sum(usage × price)
invoices not matching usage
5
limit
≠ incident opened, 5 records
after deploy 91d0be2 “batch usage aggregation”
ai investigation
  • 11 accounts share one duplicated batch id
  • traced to 91d0be2 “batch usage aggregation” metering/batch.go:132
  • over-billed total $ 6,140.00 before invoices are sent

The rule runs before invoices are finalised, so the fix happens before a single customer sees the wrong number.

The starter rule pack

The rules most teams in this space start with. Each one is a query against your own tables, adjusted to your schema during setup.

rule protects runs
usage-event-counted-once Double counting 15 min
invoice-matches-usage Wrong invoices before invoicing
credits-not-negative Unpaid usage 5 min
usage-in-period Period errors 1 hour
trial-limits-applied Free usage leaks 1 hour
price-matches-catalog Pricing drift on each deploy

How it fits your stack

The agent reads your usage and invoice tables where they already live: an operational database or the warehouse your metering pipeline writes to.

Rules can be scheduled right before your invoicing run, so they act as a gate rather than an after-the-fact report.

Common questions

Our usage lives in a warehouse, not Postgres.

Warehouse sources such as ClickHouse, BigQuery and Snowflake are on the way. Postgres, MySQL and SQL Server work today.

Can it block an invoice run?

It can alert or call a webhook when a rule fails, which your invoicing job can check before it runs.

Does it see customer data?

Only the columns you include in a rule’s result. Raw events stay with the agent.

Next industry
Logistics and inventory
Read →

Check the invoice before the customer does.

We’re onboarding a few usage-based teams first. Tell us how your metering works.

Join waitlist