GET /v1/usage returns the calling workspace's month-to-date usage: per-resource
meter totals, an advisory cost estimate, the real billing projection when the
caller may see it, and a coverage record describing how complete the totals are.
Read it before the invoice arrives to reconcile what you consumed against what
you will be charged.
This endpoint is a Bex extension — Render's public REST API has no
usage or billing endpoints — so it is documented here rather than in the
Render-parity API reference. The same month-to-date verb
also answers GraphQL Query.usage and the MCP get_usage tool with identical
semantics; the REST and MCP surfaces return identical JSON.
For payment readiness and who can bind a payment method, start with Billing setup. For time-series telemetry instead of billing meters, see Metrics.
Who can read usage
Any workspace member can read usage. The billing projection — real cost,
finalized invoices, and credit balance — is attached only for callers holding
the billing relation (the admin or billing role, can_manage_billing).
Everyone else still gets usage rows and the advisory estimate.
A third-party human token carrying only bex.read is treated as not privileged
even when the delegated user holds a billing role, so integrations authorized
through User-authorized OAuth see estimate-only
payloads. See Workspaces, members, & roles.
Read the current month
Authenticate as in REST & GraphQL API (an API key exchanged for a short-lived Bearer [REDACTED] then:
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $BEX_TOKEN" \
"$BEX_API_URL/v1/usage" | jq .The response echoes the period it covers along with one entry per metered resource:
{
"workspaceId": "wks_123",
"period": "2026-09",
"services": [
{
"serviceId": "srv_abc",
"serviceName": "web",
"resourceKind": "service",
"rows": [
{ "kind": "instance_seconds", "tier": "standard", "total": 521013 },
{ "kind": "egress_bytes", "total": 88173902 },
],
},
],
"estimatedCost": { "totalUsd": "4.17", "meters": [/* … */], "resources": [/* … */] },
"billing": { "currentCost": {/* … */}, "invoices": [] },
"coverage": { "state": "complete", "through": "2026-09-18T11:00:00Z", "degradedSources": [] },
}Query another workspace with ?ownerId=<workspace-id>; an id the caller is
not a member of is refused with 403. Read a past month with
?period=YYYY-MM (below).
Resources you already deleted keep the name their usage accrued under, marked
with "deleted": true, so a charge keeps naming its resource after deletion.
When Bex never recorded a name for an id, presenters fall back to the id.
Meters and units
Totals are in the natural unit of each kind. resourceKind is one of
service, postgres, key_value, or sandbox.
| Kind | Unit | Metered on |
|---|---|---|
instance_seconds | seconds | Services and datastores; tier names the plan tier |
egress_bytes | bytes | Services and datastores |
build_seconds | seconds | Services (builds) |
storage_gb_seconds | GB-seconds of average used volume | Datastores |
sandbox_compute_seconds | milli-vCPU-equivalent seconds | Sandboxes |
disk_gb_seconds | GB-seconds of provisioned disk | Service disks (reserved capacity, running or not) |
Underneath, meters are recorded hourly and folded into monthly aggregates once they age out of the hot window (three calendar months by default); the endpoint always answers month-to-date totals, never hourly detail.
Each meter advances on an independent cursor, so one stalled source never holds the other meters back — which is exactly what the coverage record reports.
Coverage states
coverage.state describes the evidence behind the totals. Never present a
non-complete state as a settled amount.
| State | Meaning | What to do |
|---|---|---|
complete | Every source stream is contiguous through through | Reconcile against the invoice |
partial | Some meters lag; degradedSources names them and through bounds the contiguous prefix | Treat every total as provisional; retry later for the remainder |
unknown | No evidence record (including every historical month) | Do not reconcile; the totals carry no completeness claim |
through is the common end of every active source stream's contiguous hourly
prefix. It is absent for unknown and never inferred for historical periods:
a past month always reports unknown because the evidence record is only kept
for the current month. A failed window is retried on the next hourly pass
without a restart, so partial usually converges to complete on its own.
Estimate semantics
estimatedCost is advisory. totalUsd is always present ("0.00" when there
is no billable usage); the meters breakdown omits lines whose rounded cost is
under a cent, while the resources breakdown keeps every metered line,
including free tiers and sub-cent costs — it is the only place that shows how
much was consumed, not just what it costs.
Absent billing means no billing contract data, never zero: the workspace
may have no contract, be comped or excluded, have billing disabled, or the
Stripe read may have degraded. When billing is present, currentCost is the
real Stripe-computed cost and invoices holds finalized invoices; reconcile
the estimate against those rather than treating the estimate as the charge.
Read a past month
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $BEX_TOKEN" \
"$BEX_API_URL/v1/usage?period=2026-08" | jq .coverageperiod must be a calendar month as YYYY-MM. A malformed value is a 400
— Bex refuses to substitute a different month for a misspelled one, because
usage figures drive billing conversations. A current or future month clamps to
now (month-to-date); a past month returns that month's end. The response echoes
the period actually used.
Reconcile before the invoice
- Read the current month and check
coverage.state. Proceed only oncomplete; onpartial, notethroughand the degraded sources and retry after the next hourly pass. - Compare
estimatedCost.totalUsdwithbilling.currentCost. A gap usually means credits, a comped period, or pricing the estimate does not model — the billing projection is authoritative. - Walk
estimatedCost.resourcesto find which service or datastore dominates, then confirm against Metrics or scale down with Scaling.
The usage-report example (also listed
in the examples catalog) automates this read: it prints
the per-resource table with a coverage banner, labels non-complete totals as
provisional, and never mistakes absent billing data for zero. Download it as
usage-report-latest.zip
(checksum). Source pin: Bex
6f2975248.