Skip to content
Hardcount
Run it locally
Pre-1.0 · one maintainer · Stripe and cards only · no SDKs (client libraries) yet · no production users yet. Docs describe v0.9.1 (29 Oct 2026) · What’s new →

Usage totals

GET
/v1/usage-events/aggregate
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.

customer_id
string
meter_id
string
from
string

Events at or after this time. RFC 3339, or a date (YYYY-MM-DD) meaning 00:00:00 UTC.

to
string

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.

dimensions
string

Comma-separated key=value pairs matched against event dimensions, same syntax as GET /v1/usage-events. Example: model=gpt-4o,token_type=input.

tz
string

IANA time zone for the calendar days of by_meter[].daily (default UTC). An unknown name returns 422.

Totals

Media typeapplication/json
object
total_events
required
integer
total_units
required

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.

string
active_meters
required

Distinct meters among the matching events.

integer
active_customers
required

Distinct customers among the matching events.

integer
by_meter
required

One row per meter, largest total first.

Array<object>
object
meter_id
required
string
total
required

Plain sum of reported quantities, as a decimal string.

string
aggregation
required

The meter’s aggregation (sum, count, max, last), which every price of the meter bills under. Empty when unknown.

string
value
required

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.

string
events
required
integer
customers
required

Distinct customers with events on this meter.

integer
peak
required

Highest single reported quantity, as a decimal string.

string
daily
required

One entry per calendar day (in tz) with events, oldest first.

Array<object>
object
date
required
string format: date
value
required

The day’s usage under the meter’s aggregation.

string

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.

Media typeapplication/json
object
error
object
type

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.

string
code
string
message
string
request_id
string
param

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.

string

Example

{
"error": {
"type": "invalid_request_error"
}
}