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 →

Get the customer's usage and cost for a period

GET
/v1/customers/{id}/usage
curl --request GET \
--url http://localhost:8080/v1/customers/example/usage \
--header 'Authorization: Bearer <token>'

Usage per meter on the customer’s active and trialing subscriptions, priced the same way the invoice prices it. With no from and to, the period is the current billing cycle of the subscription whose cycle started last, as of the customer’s current time (the test clock’s time for a customer on a test clock). A trialing subscription’s cycle starts when its trial ends, so it is not picked before then, unless no subscription’s cycle has started. Send both or neither.

Errors: 404 if the customer does not exist. 422 when only one of from/to is sent, when from is not before to, when the window is longer than one year, or (code customer_has_no_subscription) when no period is sent and the customer has no subscription with a current cycle.

Decimal quantities are returned as strings. If the daily series fails to load, buckets is empty and warnings says so.

id
required
string
from
string

Start of the window. RFC 3339 instant or YYYY-MM-DD (start of that day, UTC).

to
string

End of the window, exclusive. RFC 3339 instant or YYYY-MM-DD (23:59:59.999999 UTC that day, so the day is included).

Usage for the period.

Media typeapplication/json
object
customer_id
required
string
period
required

The window the response covers. With no from and to (current_billing_cycle), each subscription is rated over its own current billing period, and the period runs from the earliest start to the latest end of those periods. A meter’s totals and daily buckets cover its own subscription’s whole period, including usage a threshold invoice already billed.

object
from
required
string format: date-time
to
required
string format: date-time
source
required

current_billing_cycle: no from and to were sent, and the amounts are what the period’s invoices bill. explicit: the window you sent. Its amounts are an estimate, so a past window can differ from its invoices. Only active and trialing subscriptions are counted: the usage of a canceled subscription is left out. Each subscription’s usage in the window is priced at the prices of its current billing period.

string
Allowed values: current_billing_cycle explicit
subscriptions
required

One entry per item of each active or trialing subscription. A subscription with several plans appears once per plan, with the same id.

Array<object>
object
id
required
string
plan_id
required
string
plan_name
required
string
currency
required
string
current_period_start
required
string format: date-time
current_period_end
required
string format: date-time
meters
required
Array<object>
object
meter_id
required
string
event_name
required
string
meter_name
required
string
unit
required
string
currency
required
string
total_quantity
required

Decimal string.

string
total_amount_cents
required
integer format: int64
prices
required

One row per (plan, price) that took usage, and a no_price row per plan for the usage no price of that plan took. Two plans can price one meter differently.

Array<object>
object
price_id

Absent on a no_price row.

string
plan_id
required
string
dimension_match

The labels the price takes. Absent for a price that takes every event.

object
key
additional properties
string
quantity
required

Decimal string.

string
amount_cents
required
integer format: int64
unit_amount_decimal

Price per unit in cents, as a decimal string; the same figure the invoice line shows.

string
no_price

True for usage no price of the plan took. Hardcount bills nothing for it, and it is left out of the meter’s totals.

boolean
totals
required

One entry per currency.

Array<object>
object
currency
required
string
amount_cents
required
integer format: int64
warnings
required

Problems found working out this usage, in words, such as usage that no price takes or a meter whose usage went below zero.

Array<string>
buckets
required

One entry per UTC day in the period, including days with no usage.

Array<object>
object
bucket_start
required
string format: date-time
per_meter
required

Quantity per meter ID for that day, as a decimal string.

object
key
additional properties
string

Example

{
"period": {
"source": "current_billing_cycle"
}
}

Customer not found.

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"
}
}

Bad or missing period (param is from, to or period).

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"
}
}