Usage totals
const url = 'http://localhost:8080/v1/usage-events/aggregate';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url http://localhost:8080/v1/usage-events/aggregate \ --header 'Authorization: Bearer <token>'Event count, quantity totals, and a per-meter breakdown over every
usage event matching the filters (no paging). Each by_meter row
carries value, the meter’s usage under its own aggregation: a
sum, an event count, each customer’s peak (Maximum) or each
customer’s latest reading (Latest value), added across customers.
total stays the plain sum of reported quantities. total_units
adds quantities across all meters whatever their units, and is kept
for compatibility only.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Events at or after this time. RFC 3339, or a date (YYYY-MM-DD) meaning 00:00:00 UTC.
Events before this time, exclusive. RFC 3339, or a date (YYYY-MM-DD) meaning 23:59:59.999999 UTC that day, so the day is included.
Comma-separated key=value pairs matched against event dimensions,
same syntax as GET /v1/usage-events. Example:
model=gpt-4o,token_type=input.
IANA time zone for the calendar days of by_meter[].daily
(default UTC). An unknown name returns 422.
Responses
Section titled “Responses”Totals
object
Sum of all matching quantities across meters, as a decimal
string. It adds different units and ignores each meter’s
aggregation; use by_meter[].value instead.
Distinct meters among the matching events.
Distinct customers among the matching events.
One row per meter, largest total first.
object
Plain sum of reported quantities, as a decimal string.
The meter’s aggregation (sum, count, max, last),
which every price of the meter bills under. Empty when
unknown.
Usage under the meter’s aggregation, as a decimal string.
max and last take each customer’s peak or latest
reading in the window and add them across customers.
Billing applies them per billing period.
Distinct customers with events on this meter.
Highest single reported quantity, as a decimal string.
One entry per calendar day (in tz) with events, oldest first.
object
The day’s usage under the meter’s aggregation.
Example generated
{ "total_events": 1, "total_units": "example", "active_meters": 1, "active_customers": 1, "by_meter": [ { "meter_id": "example", "total": "example", "aggregation": "example", "value": "example", "events": 1, "customers": 1, "peak": "example", "daily": [ { "date": "2026-04-15", "value": "example" } ] } ]}validation_error: a malformed dimensions pair, an unknown tz, a from or to that cannot be parsed, or to before from.
object
object
One of invalid_request_error, authentication_error,
rate_limit_error or api_error. Every error the API
answers has this shape, including an unknown path (404,
code route_not_found) and a method the path does not take
(405, code method_not_allowed, with an Allow header).
The few exceptions are listed in docs/api-surface.md.
The request field the error is about. Sent only when the error
names one. A request body may hold only the fields its
operation lists, spelled and cased as listed: any other
field, or one the server sets (such as id), is refused
with 422 and param naming it. An operation with no request body lists no fields: send
no body, {} or null. The Stripe and Postmark webhooks and
the LiteLLM callback take their sender’s body as it comes.
Example
{ "error": { "type": "invalid_request_error" }}