Reporting usage
A meter turns reported usage into a billable quantity. You report events; the meter's aggregation method decides what the period is billed on. The method is chosen when the meter is created and freezes once any usage exists against it, because changing how a quantity is derived would restate periods that have already been invoiced.
Reporting an event
Code
Identify the meter by meterId or meterName; one of the two is required. See
the API Reference for the full schema.
The response is an acknowledgement, not a recorded event
Reporting is asynchronous. A successful call answers 202 with
{"status": "queued", "requestId": "...", "idempotencyKey": "..."} — the event
is accepted and recorded a moment later. A key you have already used answers
200 with "status": "duplicate" and records nothing further.
So a 202 means the report will be counted, not that it already has. Nothing
downstream needs you to wait for it: the quantity is read when the period is
billed, long after ingestion.
Retries are safe when the key is derived
The x-api-idempotency-key header is required, and it is yours to choose:
reporting the same key twice records one event. Derive it from what you are
reporting — the customer, the meter, and the period or batch. A random key, or
one built from the clock at call time, makes a retry after a network timeout a
second charge, which is what this header exists to prevent.
The same rules apply as everywhere else on the API; see Idempotency.
Which period an event falls in
timestamp decides that, and defaults to now. It is the usage instant rather
than the reporting instant, so a nightly job reporting yesterday's consumption
sends yesterday's timestamp.
An event timestamped into a period that has already been invoiced leaves that invoice unchanged. The period was billed on what the meter held at the time.
What makes usage billable
Reporting and billing are independent. A meter accepts events for any customer at any time — there is no subscription check on the way in, so you can report as much as you like, as early as you like.
Billing reads that usage back one subscription at a time. An invoice covers a
subscription's billing period and bills the usage recorded inside it, so usage
sitting in a stretch of time no subscription covers is stored and never billed:
there is no period to bill it on. A report that returned 202 and never reached
an invoice is almost always this — most often usage recorded before the
subscription started.
Backdating picks that usage up
Giving a subscription a start date in the past extends its coverage back over usage you already reported, and the first invoice bills it. That is the default, and it is what you want when the reporting ran ahead of the paperwork.
You are asked before it happens. Assigning, copying or replacing a subscription with a past start date lists the usage already recorded in that window, one row per meter, with the option to discard it instead. Discarding sets a floor on that subscription and meter: usage recorded before the assignment is excluded from every invoice, and usage from the assignment onward bills normally. A floor only ever moves forward, so a repeated or out-of-order discard can never re-admit units an earlier one excluded.
Meters aggregating on last are listed but cannot be discarded. They report a
level the customer currently holds rather than consumption, so flooring their
history would bill 0 for a resource that is still in use.
Aggregation methods
| Method | The period is billed on | Use it for |
|---|---|---|
sum | The total of every quantity reported. | Tokens, GB transferred, API calls. |
count | How many events arrived. The quantity is ignored. | Deliveries, runs, webhook sends. |
last | The most recent quantity — a level. | A current seat count. |
max | The highest quantity reported. | Peak seats or connections held across the whole account. |
max_per_dimension | The peak each dimension reached, added together. | Per-seat, per-device or per-user peaks. |
The last two differ in a way worth being deliberate about. max bills the
biggest number anyone reported, so for a per-subject charge the busiest subject
sets the price for the whole account. max_per_dimension bills what each
subject peaked at, added together.
Dimensions
A dimension names what the quantity is measured per. Only max_per_dimension
reads it; every other method ignores it.
Code
Reporting a level per subject once a day gives a period total of each subject's own peak:
| Day | seat-a | seat-b | Account total that day |
|---|---|---|---|
| 1 | 1 | 3 | 4 |
| 2 | 4 | 0 | 4 |
| 3 | 1 | 3 | 4 |
max_per_dimension bills 7: seat-a peaked at 4 and seat-b at 3. max
bills 4 and sum bills 12.
No calculation over the daily totals reaches 7, because the subjects peaked on different days and the totals no longer hold that. This is why the dimension rides the event rather than being added up first.
A dimension is a grouping key
It identifies something that persists across reports, so that "the peak this subject reached" has a meaning. A value that varies per report — a request id, an event id, a timestamp — gives every event its own group and bills the maximum of each event by itself.
Descriptive detail belongs in metadata, which is stored with the event and
never aggregated on.
A meter refuses a new dimension once it carries too many distinct values, so an accidental high-cardinality key surfaces as a rejected report rather than an invoice that grows without limit. Values already in use keep working, and a dimension is capped at 100 characters.
Omitting the dimension
An event with no dimension groups under a single bucket, so a
max_per_dimension meter fed by a writer that never sets one bills the same as
max. That keeps a misconfigured meter on a defensible number while the
reporting is corrected.
Required scope and license
Reporting usage needs the meter-report scope on the API key
(API keys) and the Subscription license
(Licenses). A key without the scope gets 403; a tenant
without the license gets 403 with code LICENSE.REQUIRED.