Aggregate cost across a time window
const url = 'https://example.com/v1/cost/aggregate?groupBy=example&limit=1000&includeDescendants=false&scopeKind=tenant&inherit=true';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 'https://example.com/v1/cost/aggregate?groupBy=example&limit=1000&includeDescendants=false&scopeKind=tenant&inherit=true' \ --header 'Authorization: Bearer <token>'Primary consumer path for dashboards. groupBy is required (comma-separated dimensions from the closed set); time range is required (both from and to, or both omitted for the default last-30-days window echoed back in timeRange). Filters compose on top of the time window. ?scopeKind + ?scopeId narrow the aggregate to a scope: org covers every project in the org, so one call sums an org’s spend. It needs read on the scope, and across projects (no scope, the tenant, or an org) it counts only the projects the caller may read, and records with no project; a tenant admin’s counts every project. Each group, and the total, carries its cost and its token sums (tokens). groups is ordered by totalUsd, highest first (ties by key), and capped at limit (default 1000): truncated and totalGroups say when there were more, and the totals still cover every record. For every record, page through /v1/cost/records. inherit has no effect on cost records, which always belong to a project.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Comma-separated list of dimensions to aggregate over. Each value must be one of agentId | runId | category | providerId | day | month | tenant | conversationId | model | servedModel | projectId | orgId | rootRunId | flowId. model is the model actually called; servedModel the exact version the vendor reported; orgId the org of the record’s project. Duplicates collapse.
The most groups to return: the most expensive ones (groups is ordered by totalUsd, highest first). 1 to 10000, default 1000. When there were more, truncated is true and totalGroups says how many; the totals still cover every record.
ISO 8601 timestamp; records with occurredAt >= from. Required on /v1/cost/aggregate (or both endpoints omitted for default last-30-days window).
ISO 8601 timestamp; records with occurredAt < to (exclusive). Required on /v1/cost/aggregate (or both endpoints omitted for default last-30-days window).
Filter to a specific category (llm.inference, tool.invocation, storage.write, sandbox.exec, …). Exact match.
Filter records to this provider id (exact match).
Filter records to this agent id (exact match).
Filter records to this run id (exact match).
Filter records to this conversation id (exact match).
Filter model calls to this model, the one actually called (exact match).
Filter model calls to the exact model version the vendor reported (exact match).
Every record of the run tree whose root is this run: a flow run and the agent turns and sub-flows it started.
With runId: the run’s records and those of every run it started, at any depth. true or false (default).
Discriminator for the ?scopeKind + ?scopeId + ?inherit triplet. Tenant carries no id (implicit from session); org/project require scopeId.
Optional scope discriminator. If absent, no scope filter is applied.
Required IF scopeKind is org or project. MUST be absent if scopeKind=tenant (tenant is implicit from the session). Malformed combinations return 400 scope-invalid.
Default true. false = literal-at-this-scope only (admin/audit view). Load-bearing for policy/config-scoped resources (mcp-endpoints); documented no-op for content-scoped resources (agents/flows/tools/…).
Responses
Section titled “Responses”Aggregate rollup.
object
The most expensive groups first (totalUsd descending, ties by key), at most limit.
object
One entry per requested groupBy dimension. null = distinct “unattributed” bucket (records had no value for that dimension).
object
object
How many groups there were before the limit cap. Absent from a runtime before 0.1.5.
true when there were more groups than limit: groups holds the most expensive ones, and totalUsd / totalRecords / tokens still cover every record. Absent from a runtime before 0.1.5.
object
object
The dimensions the server actually grouped by — echoed so callers can round-trip the response without re-parsing the request URL.
Example
{ "groupBy": [ "agentId" ]}Missing / malformed groupBy, unknown dimension, missing one endpoint of the time range, or from > to.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Missing / malformed / expired / revoked bearer token.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}