Designing Billing Meters: Value Types, Units, and the Four Aggregations That Decide the Invoice

A billing meter is a small schema decision with invoice-sized consequences: value type, aggregation (sum, count, max, unique_count), and unit decide what you can ever bill. What each aggregation means, the mistakes that force re-metering, and the five lines to write down before your first event.

8 min read

usage meteringbilling metersusage-based pricingmetering design
TL;DR: A billing meter is a tiny schema decision with invoice-sized consequences. Before you send a single usage event, decide three things per meter: the value type (number or string), the aggregation (sum, count, max, or unique_count), and the unit your customer will read on the invoice. Sum meters bill volume, count meters bill occurrences, max meters bill peaks, and unique_count meters bill distinct actors. Picking the wrong one is not a config tweak later - it is a re-metering project, because historical events cannot be re-aggregated into a shape they never carried.

Why the meter, not the price, is the real design decision

Most teams obsess over the price point and improvise the meter. It should be the other way around. A price is a number you can change tomorrow with a pricing-page edit. A meter is a data contract: every event you ingest is shaped by it, every rollup is keyed by it, and every invoice line inherits its semantics. Change the price and last month's invoices stay valid. Change what a meter means and you have two eras of incompatible history.

In UsageBox a meter is created once with a name, a value_type, an optional unit (uom), and an agg_type, and it gets a generated ingest_key that your events reference. That is the whole surface, and each field is a decision worth five minutes of thought.

Value type: number or string

Numeric meters carry quantities: request counts, token counts, gigabyte-hours, minutes of transcription. String meters carry identities: a user id, a device id, a filename. The split matters because it constrains what aggregation can do. You can sum quantities; you cannot sum identities. UsageBox enforces this at meter creation: number meters allow sum, count, and max, while string meters allow count and unique_count.

The classic mistake is sending an identity as a number (a numeric user id summed into nonsense) or a quantity as a string (a "1024" that can only ever be counted, never added). If you catch yourself casting, stop and ask which question the invoice must answer: how much, how often, how big, or how many distinct.

The four aggregations, and the invoice each one produces

AggregationQuestion it answersTypical meterFailure mode if misused
sumHow much volume this month?API calls with weight, tokens, GB transferredRetry storms and replays inflate the bill unless ingestion is idempotent
countHow many events this month?Jobs run, reports generated, webhooks deliveredCounting free or internal events that should never bill
maxWhat was the peak this month?Concurrent seats, peak storage, largest clusterOne traffic spike prices the whole month; customers remember it
unique_countHow many distinct actors this month?Monthly active users, unique devices, distinct reposUnstable identifiers (session ids instead of user ids) silently multiply "users"

Defaults exist for the impatient: numeric meters default to sum, string meters default to count. Defaults are fine for a prototype. For a meter customers pay against, choose explicitly and write one sentence in your docs saying what the meter means. That sentence is the thing support will quote in a billing dispute.

Units are a promise to a human

The uom field ("calls", "tokens", "GB", "seats") never changes a computation, and that is exactly why it is easy to neglect. It is the only part of the meter a customer actually reads. A meter that bills in "requests" but ingests weighted values (a heavy endpoint counting as 5) will produce invoices where the numbers do not match the customer's own logs. Either meter raw requests and price tiers separately, or name the unit honestly ("request units"). Mismatched units are the top source of "your dashboard says 12,000 but my logs say 3,000" tickets.

Granularity: fewer meters, more dimensions

The tempting design is one meter per feature per plan per region. Resist it. Every meter is a contract you maintain forever, and a meter-per-variant explosion turns pricing changes into schema migrations. The robust pattern is a small set of meters that describe physics (requests, compute seconds, storage, distinct users) with plans and charges layered on top. If you find yourself creating "api-calls-pro-eu" you are encoding pricing into the meter, and the next pricing change will hurt. For splitting cost by customer and model, see Kata #4 on per-customer, per-model dimensions.

Decisions you cannot cheaply reverse

  1. Aggregation semantics. A month of sum events cannot become a max meter retroactively; the peaks were never recorded.
  2. Identifier choice for unique_count. Switch from user id to email mid-month and the same person counts twice.
  3. What counts as billable. If health checks and retries were metered from day one, excluding them later shrinks revenue and makes history incomparable. Decide the exclusion list first - our piece on bot and crawler traffic covers the non-human half of that list.

What you can change freely: price per unit, tiers, plan mapping, and the unit label. Design meters for the questions, price them for the market.

The honest take

Meter design is unglamorous and takes an afternoon, which is why it is usually skipped and then repaid as a quarter of billing archaeology. Write down, per meter: value type, aggregation, unit, identifier (for uniques), and the exclusion list. Five lines. Every billing system you might ever migrate to - including UsageBox - will reward you for having them, and idempotent ingestion handles the delivery half of correctness.

Key Topics

  • usage metering
  • billing meters
  • usage-based pricing
  • metering design

Related Articles

Explore more articles on similar topics to deepen your understanding of usage-based billing.

Per-Seat Pricing Can't Survive Agentic Users: The SaaS Margin Math That Breaks in One Loop

If you sell software at a flat per-seat price and your product calls an LLM that bills per token, your margin is a bet t...

6 min readRead more

Idempotent Usage Metering: Deduplicating Events and Handling Late Arrivals Without Double-Charging

A usage meter that bills customers must count each event exactly once even when delivered twice, and still get the count...

9 min readRead more

Metering Monthly Active Users for Billing: unique_count Beats Log Analytics

Analytics MAU dedupes by cookie and misses blocked clients; billable MAU must be exact and reproducible. How to meter di...

8 min readRead more

Explore More Articles

Discover our complete collection of usage-based billing guides and implementation patterns.

View all articles