Skip to content

Read your workspace's usage

View as Markdown
GET
/v1/usage
curl --request GET \
--url 'https://example.com/v1/usage?from=2026-04-15T12%3A00%3A00Z&to=2026-04-15T12%3A00%3A00Z' \
--header 'Authorization: Bearer <token>'

Your workspace’s usage records aggregated by the dimensions in groupBy: each group’s count, the sum of its quantities, and its first and last times. Never a record’s content. Over the projects you may read: a tenant admin’s covers every project and the records with none; anyone else’s, only the projects they may read, and one they can’t read is absent rather than an error. watermark: every record at or before it is in the answer, so re-read a window until its watermark is past the window’s end; every page of one read carries the same watermark. A runtime that doesn’t count usage (KINDGI_USAGE_METERING unset or off) answers 404. Model-call cost is on /v1/cost.

from
required
string format: date-time

Records at or after this time: a time with a zone, such as 2026-11-01T00:00:00Z.

to
required
string format: date-time

Records before this time. At most 92 days after from.

groupBy
string

Comma-separated, each once: project, agent, kind, class, state, day (the UTC date). Default project,kind.

kind
string

Only these kinds, comma-separated (run.started, run.ended, approval.requested, approval.decided, llm.inference, llm.embedding, project.production).

class
string

Only these run classes, comma-separated (production, staging, dry-run, replay, eval, child).

state
string

Only these states, comma-separated: on, off (project.production); completed, failed, cancelled (run.ended); escalation (approval.requested, an escalation’s next tier); approved, rejected, withdrawn, escalated, expired (approval.decided).

limit
integer
>= 1 <= 10000

Groups a page: 1 to 10000, default 1000.

cursor
string

The previous page’s nextCursor.

projectId
string format: uuid

Only this project. One you can’t read gives an empty answer.

A page of groups.

Media typeapplication/json
object
data
required
Array<object>

One group: the dimensions it’s grouped by (only those), then its count, the sum of its quantities, and its first and last times.

object
tenantId

The tenant, on the operator’s read across tenants.

string format: uuid
projectId

Absent for a record with no project; a tenant admin’s read includes those, and the CLI shows them as (none).

string
agentId

Absent for a record with no agent; the CLI shows those as (none).

string
kind

What was counted: run.started, run.ended, approval.requested, approval.decided, llm.inference, llm.embedding, project.production. A runtime may count more kinds later: show one you don’t know as it is.

string
class

The class of the run a record counts or belongs to, fixed when the run was created: production, staging, dry-run, replay, eval, child. A record with no counted run has none. A runtime may add classes later: show one you don’t know as it is.

string
state

The record’s state, by kind: on, off (project.production); completed, failed, cancelled (run.ended); escalation (approval.requested, an escalation’s next tier); approved, rejected, withdrawn, escalated, expired (approval.decided). Other kinds have none.

string
day

The UTC date, YYYY-MM-DD.

string
/^\d{4}-\d{2}-\d{2}$/
count
required

Records in the group.

integer
quantity
required

The sum of their quantities: milliseconds for run.ended, tokens for model calls, and 1 for every other record, so a group of those has a quantity equal to its count.

number
firstAt
required
string format: date-time
lastAt
required
string format: date-time
watermark
required

Every record at or before this time is in the answer; a later one may not be yet. Re-read a window until its watermark is past the window’s end. Every page of one read carries the same watermark.

string format: date-time
nextCursor

More groups: pass it as cursor. Absent on the last page.

string
Examplegenerated
{
"data": [
{
"tenantId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"projectId": "example",
"agentId": "example",
"kind": "example",
"class": "example",
"state": "example",
"day": "example",
"count": 1,
"quantity": 1,
"firstAt": "2026-04-15T12:00:00Z",
"lastAt": "2026-04-15T12:00:00Z"
}
],
"watermark": "2026-04-15T12:00:00Z",
"nextCursor": "example"
}

A window, filter, limit or cursor this route can’t read (bad-input), naming which.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Missing / malformed / expired / revoked bearer token.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The projects you may read can’t be listed on this deployment, so usage across projects can’t be limited to them (permission-denied): ask for one with projectId.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

See also