Usage
Read the usage ledger, summarize GPU time and spend over a window, and report reserved capacity against it.
Introduction
Usage is recorded as an append-only ledger, one row per worker state transition, each carrying the GPU count and the rate that applied. Everything else here is derived from it on read. Pricing explains what is billed and why.
Totals are never stored, so a window that cannot be priced in full fails rather than reporting a smaller number. A total that silently omits usage is a wrong number the caller cannot see is wrong.
List usage events
Append-only billing telemetry. One row per worker state transition. appId narrows the page to one app, the copy environment selects (production by default); without appId the page spans the organization and environment narrows nothing.
Events are drawn on when the transition happened, not when it was recorded, so ingest lag never moves one across a boundary. busy never appears: it describes queue occupancy rather than a change in the worker's life, and a worker costs the same whether it is serving or waiting.
Request
limit
integerint32min: 1max: 100default: 20Maximum number of items to return.
cursor
stringOpaque pagination cursor returned by a previous call, as
nextCursoror, on the operations that offer one,prevCursor.
appId
stringmin: 6max: 30Immutable app identifier. Unique among the authenticated organization's live apps in one environment: it cannot be changed after creation, it becomes available again once the app it named reaches
deleted, and the same id may run once in each environment as a separate copy.
environment
stringmin: 1max: 63The environment the request addresses. An app id names one copy per environment, so this parameter completes the app's address:
appIdtogether withenvironmentselects the copy. The app list and the app summary are limited to the environment, and an app, build, endpoint, worker, event, usage or attached-secret cursor is valid only in the environment it came from. A metric query that names no app covers the whole organization, and a log query covers this environment; a metric query expanded by app returns only the apps live in this environment. Omitted meansproduction. A name the organization has no live environment under returns404.
from
string (date-time)date-timeInclusive lower bound on event time (RFC 3339).
to
string (date-time)date-timeExclusive upper bound on event time (RFC 3339).
Response
nextCursor
stringnullableCursor for the next page. Null when there are no more items.
data
object[]Array items10 properties each
id
string (uuid)requiredUUID v4
appId
stringrequiredmin: 6max: 30Immutable app identifier. Unique among the authenticated organization's live apps in one environment: it cannot be changed after creation, it becomes available again once the app it named reaches
deleted, and the same id may run once in each environment as a separate copy.
environment
stringrequiredmin: 1max: 63The environment the app's copy runs in.
workerId
string (uuid)requiredUUID v4
eventType
stringrequiredStatus the worker transitioned into. The ledger emits a subset of
WorkerStatus.busynever appears (queue occupancy, not a pod lifecycle transition). Consecutive rows of one worker can carry the same status.Possible values9 values
gpuCount
integerrequiredint32
gpuType
stringmin: 1max: 64GPU type the worker held at the transition. Absent when the worker held no GPU.
pricePerSecond
objectCatalog price per GPU per second in force at
occurredAt, resolved from the catalog history. Absent whengpuTypeis absent or the catalog history has no applicable price. This is the positive pay-as-you-go rate whatever covered the time. Reserved capacity is not a discount on it: coverage is reported byGET /v1/usage/summaryand never by a rate of zero.
occurredAt
string (date-time)requireddate-timeWhen the transition happened. This is the event time the
fromandtofilters apply to, and the field to bill on.
createdAt
string (date-time)date-timeWhen the event was recorded. Audit only. May lag
occurredAt.
Errors
| Status | When |
400 | The request was malformed and could not be parsed (e.g. invalid JSON). A well-formed request that fails validation returns 422 instead.
|
401 | Missing or invalid credentials |
404 | Resource not found |
422 | The request was well-formed but semantically invalid (e.g. a missing or out-of-range field). A request that could not be parsed returns 400. The errors array carries one entry per offending field.
|
500 | Unexpected server error |
503 | A required service is temporarily unavailable |
Summarize usage
GPU time and spend for the authenticated organization, or for one of its environments, aggregated over a half-open window and grouped by the dimensions asked for. environment narrows what is reported, not what is measured: a capacity commitment covers the organization's concurrent GPUs in every environment, so one environment's figures are its share of that coverage.
Every figure is derived on read from the immutable usage ledger, the effective-dated price catalog and the organization's capacity commitments. Two consequences follow. The window is bounded, because the read folds every event of every worker in it. And a worker whose recorded life cannot be priced fails the request rather than being left out of the totals, because a total that silently omits usage is a wrong number a caller cannot see is wrong. These failures return 500, with no partial totals.
paygSpend is provisional pay-as-you-go accrual, not a settled charge. It excludes whole-second finalization rounding and ledger adjustments. paygEquivalentValue prices the same time at the catalog rate whatever covered it, so the difference between them is what a capacity commitment, or the platform, paid for. Time covered by a capacity commitment or by the platform settles at zero, so only pay-as-you-go is drawn from credit.
paygSpend is provisional accrual, not a settled charge: it excludes whole-second finalization rounding and ledger adjustments. paygEquivalentValue prices the same time at the catalog rate whatever covered it, so the gap between the two is what a reserved capacity commitment, or the platform itself, paid for. Both settle at zero, so only pay-as-you-go time is drawn from credit.
timezone takes an IANA name and decides where a calendar day and a clock hour begin, UTC when omitted. from and to stay exact instants either way, so the window is the same and only the buckets move.
Request
from
string (date-time)date-timeInclusive lower bound on billable time (RFC 3339). Defaults to 24 hours before
to. The maximum elapsed window is 48 hours whengroupByincludeshour, otherwise 31 days. Timezone selection does not change this instant. An explicit zero timestamp (0001-01-01T00:00:00Z) returns422rather than selecting the default.
to
string (date-time)date-timeExclusive upper bound on billable time (RFC 3339). Defaults to now, and a value in the future is read as now. An explicit zero timestamp (
0001-01-01T00:00:00Z) returns422rather than selecting the default.
appId
stringmin: 6max: 30Report only this app's usage, the copy
environmentselects. A filter on what is reported, not on what is measured: coverage depends on every app's concurrent GPUs.
environment
stringmin: 1max: 63Report only this environment's usage. Omitted, the report covers every environment of the organization, except that
appIdalone names the app'sproductioncopy. A name the organization has no live environment under returns404.
gpuType
stringmin: 1max: 64Report only usage of this GPU type. A retired type is accepted, because usage recorded before it was withdrawn is still reportable. A type the catalog has never carried returns
422.
groupBy
string[]Dimensions to group by. An empty list returns one bucket for the whole window when there is billable time. Usage with no billable milliseconds produces no bucket, for any grouping. Each dimension appears on the bucket it was requested with and is absent otherwise. Grouped by
app, each environment's copy of an app is its own bucket. Grouped byhour, the resolved window must not exceed 48 elapsed hours, including when other dimensions are requested. The limit applies after defaults and future-end clamping.
timezone
stringmax: 255default: UTCIANA timezone name for calendar-day and clock-hour grouping, for example
Europe/London. Defaults to UTC when omitted. Empty, invalid and server-local (Local) names return422. The RFC 3339fromandtovalues remain exact instants, not local clock values. Day buckets follow local calendar dates. Repeated hours are separate occurrences; nonexistent hours produce no bucket. Offset transitions can create partial hours. Missing midnight starts its date at the first existing instant, and repeated midnight belongs to one date bucket. Empty buckets are not filled.
Response
from
string (date-time)requireddate-timeInclusive start of the reported window, as resolved.
to
string (date-time)requireddate-timeExclusive end of the reported window, as resolved.
buckets
object[]requiredArray items9 properties each
appId
stringmin: 6max: 30Present when grouped by
app.
environment
stringmin: 1max: 63Present when grouped by
app; the environment the app's copy runs in.
gpuType
stringmin: 1max: 64Present when grouped by
gpuType.
day
stringdateCalendar date in the requested timezone, UTC by default. Present when grouped by
day. A span crossing local midnight is divided between the dates it ran on.
hour
string (date-time)date-timeActual start of the local clock-hour occurrence, serialized in UTC. Present when grouped by
hour. It can precedefromfor a partial first bucket. Repeated hours have distinct starts, and an offset transition can start a partial hour.
coverage
stringPresent when grouped by
coverage.Possible values3 values
gpuMilliseconds
integerrequiredint64min: 0Billable GPU time, summed over each GPU separately. A worker holding four GPUs for one second contributes four thousand. Under billing policy
serverless-billing-v3every span is counted in whole milliseconds rounded up, so a span shorter than a millisecond counts as one; usage recorded under an earlier policy keeps the count it was recorded under. A span crossing calendar boundaries is divided so its buckets sum to the span's own count.
paygSpend
objectrequiredProvisional pay-as-you-go accrual for this time, excluding finalization rounding and ledger adjustments. Zero for time a commitment or the platform covered.
paygEquivalentValue
objectrequiredThe same time priced at the catalog rate, whatever covered it. The difference from
paygSpendis what reserved capacity saved and what the platform paid for.
total
objectrequiredThe whole window with no grouping. It carries no dimension fields, and it always equals the sum of
buckets.Properties9 properties
appId
stringmin: 6max: 30Present when grouped by
app.
environment
stringmin: 1max: 63Present when grouped by
app; the environment the app's copy runs in.
gpuType
stringmin: 1max: 64Present when grouped by
gpuType.
day
stringdateCalendar date in the requested timezone, UTC by default. Present when grouped by
day. A span crossing local midnight is divided between the dates it ran on.
hour
string (date-time)date-timeActual start of the local clock-hour occurrence, serialized in UTC. Present when grouped by
hour. It can precedefromfor a partial first bucket. Repeated hours have distinct starts, and an offset transition can start a partial hour.
coverage
stringPresent when grouped by
coverage.Possible values3 values
gpuMilliseconds
integerrequiredint64min: 0Billable GPU time, summed over each GPU separately. A worker holding four GPUs for one second contributes four thousand. Under billing policy
serverless-billing-v3every span is counted in whole milliseconds rounded up, so a span shorter than a millisecond counts as one; usage recorded under an earlier policy keeps the count it was recorded under. A span crossing calendar boundaries is divided so its buckets sum to the span's own count.
paygSpend
objectrequiredProvisional pay-as-you-go accrual for this time, excluding finalization rounding and ledger adjustments. Zero for time a commitment or the platform covered.
paygEquivalentValue
objectrequiredThe same time priced at the catalog rate, whatever covered it. The difference from
paygSpendis what reserved capacity saved and what the platform paid for.
calculatedAt
string (date-time)requireddate-timeThe instant the figures describe.
Errors
| Status | When |
400 | The request was malformed and could not be parsed (e.g. invalid JSON). A well-formed request that fails validation returns 422 instead.
|
401 | Missing or invalid credentials |
404 | Resource not found |
422 | The request was well-formed but semantically invalid (e.g. a missing or out-of-range field). A request that could not be parsed returns 400. The errors array carries one entry per offending field.
|
500 | Unexpected server error |
503 | A required service is temporarily unavailable |
Credit balance
The authenticated organization's Serverless credit pool, read as one snapshot at observedAt. Serverless credit is separate from inference credit.
availableBalance is totalBalance minus heldCredit, and can be negative. Held credit is set aside for capacity that is running or starting. It has not been spent and is unrelated to reserved capacity. An arrears account is invoiced for its usage and holds no prepaid balance, so both balances are null rather than zero.
Until Serverless billing is active for the organization, this returns 404, which is not a zero balance. The balance and the 404 are sent with Cache-Control: no-store.
A 404 here means Serverless billing is not active for the organization yet. It is not a zero balance, and the two are worth telling apart before showing a customer a number.
Response
collectionMode
stringrequiredHow the organization pays for Serverless usage.
prepaidusage draws down credit bought in advance.arrearsusage is invoiced afterwards, so the pool holds no prepaid balance.Possible values2 values
status
stringrequiredFor a prepaid pool:
healthymeans the balance covers the capacity that is running or starting.gracemeans it does not. Capacity beyond what held credit covers cannot be added, and running capacity continues while funding is awaited.drainingmeans the grace period has ended, and running capacity may be stopped until what remains fits the balance.suspendedmeans a refund took the balance below zero, and no capacity can be added until a top-up brings it back to zero or above. An arrears pool has no prepaid balance to restrict it and reportshealthy.Possible values4 values
totalBalance
objectrequirednullableThe prepaid ledger balance, held credit included. Negative when the organization owes credit.
nullfor arrears.
heldCredit
objectrequiredCredit set aside for capacity that is running or starting. It has not been spent, and it is unrelated to reserved capacity.
availableBalance
objectrequirednullabletotalBalanceminusheldCredit: the credit left to spend. Can be negative.nullfor arrears.
observedAt
string (date-time)requireddate-timeWhen these figures were read.
Errors
| Status | When |
401 | Missing or invalid credentials |
404 | Serverless billing is not active for the organization yet |
500 | Unexpected server error |
503 | A required service is temporarily unavailable |
Reserved capacity
What the authenticated organization has reserved, what it is using of it now, and what overflowed to pay-as-you-go.
One entry per commitment scope, one GPU type in one region, because compatible terms add together and cover an allocation between them. The terms that make up the scope are listed with their own dates and quantities.
Counts describe recorded billable state at the window end, so a report of a past period describes that period rather than mixing it with the present. A scope with an effective commitment appears even when nothing is using it: an idle reservation is still charged for, and is what the customer most needs to see. Scopes whose terms expired during the period remain with their historical usage and zero committed capacity at the window end.
The fixed commitment charge is not here. Serverless meters usage and does not own that charge. The commerce system invoices it from the contract schedule. Usage that cannot be priced returns 500, with no partial report.
A scope with an effective commitment is reported even when nothing is using it, because an idle reservation is still charged for. The fixed commitment charge itself is billed separately and does not appear in this response.
Request
from
string (date-time)date-timeInclusive lower bound of the reporting period (RFC 3339). Defaults to 24 hours before
to. The maximum window is 31 days. An explicit zero timestamp (0001-01-01T00:00:00Z) returns422rather than selecting the default.
to
string (date-time)date-timeExclusive upper bound of the reporting period (RFC 3339). Defaults to now, and a value in the future is read as now. An explicit zero timestamp (
0001-01-01T00:00:00Z) returns422rather than selecting the default.
Response
data
object[]requiredArray items14 properties each
gpuType
stringrequiredmin: 1max: 64Public catalog code for a supported GPU type (e.g.
h100,rtx-pro-6000). Must match anidreturned byGET /v1/gpu-types(validated at request time against the catalog). This is not the internal database row UUID.
region
stringrequiredThe region a capacity commitment applies to. One value until app placement selects a region.
Possible values1 value
terms
object[]requiredArray items4 properties each
id
string (uuid)requiredUUID v4
gpuCount
integerrequiredint32min: 1Concurrent GPUs this term reserves.
startsAt
string (date-time)requireddate-timeInclusive start of the term.
endsAt
string (date-time)requireddate-timeExclusive end of the term. An amended term ends where its replacement starts, so the two never both apply.
committedGpuCount
integerrequiredint32min: 0Concurrent GPUs reserved at
calculatedAt, across every effective term.
coveredGpuCount
integerrequiredint32min: 0Reserved GPUs in use at
calculatedAt.
unusedGpuCount
integerrequiredint32min: 0Reserved GPUs idle at
calculatedAt. Charged for, because reserved capacity is a promise of access rather than a quantity of GPU time.
paygOverflowGpuCount
integerrequiredint32min: 0Matching GPUs in use at
calculatedAtabove the reserved quantity. These are what a pay-as-you-go charge in this scope can be traced to.
from
string (date-time)requireddate-timeInclusive start of the reported period, as resolved.
to
string (date-time)requireddate-timeExclusive end of the reported period, as resolved.
coveredGpuMilliseconds
integerrequiredint64min: 0Reserved GPU time used over the period.
paygGpuMilliseconds
integerrequiredint64min: 0GPU time in this scope over the period that the reservation did not cover and pay-as-you-go charged for.
paygSpend
objectrequiredProvisional overflow accrual, excluding finalization rounding and ledger adjustments.
coveredValue
objectrequiredThe covered time priced at the catalog rate. What pay-as-you-go would have charged for it, and so what the reservation saved.
calculatedAt
string (date-time)requireddate-timeThe instant the counts describe.
Errors
| Status | When |
400 | The request was malformed and could not be parsed (e.g. invalid JSON). A well-formed request that fails validation returns 422 instead.
|
401 | Missing or invalid credentials |
422 | The request was well-formed but semantically invalid (e.g. a missing or out-of-range field). A request that could not be parsed returns 400. The errors array carries one entry per offending field.
|
500 | Unexpected server error |
503 | A required service is temporarily unavailable |