---
title: "An agent's tokens and cost per model per day"
method: GET
path: "/api/v1/agents/{id}/usage"
tags: ["Agents"]
---

# An agent's tokens and cost per model per day

`GET /api/v1/agents/{id}/usage`

## Request

- Base URL: `https://app.lastping.dev`
- URL: `https://app.lastping.dev/api/v1/agents/{id}/usage`
- Auth: API key in header `X-Api-Key`

Tokens (input, output, cache reads and writes) and cost per model per
UTC day over the range, from the daily dependency aggregate. Costs a
model call did not report are estimated from LastPing's price table
and labelled `estimated`.

Usage an agent reported only through an OTLP metrics export (for
example Cursor, which sends metrics and no traces) fills the days
and models its traces do not cover, with `origin: metrics`. Trace
and metric figures for the same day, provider and model are never
added together: the trace-derived row wins.

## Query parameters

- `range` '24h' | '7d' | '30d'
- `project` string

## Response `200`

The agent's usage.

- AgentUsageReport: The body of `GET /api/v1/agents/{id}/usage`.
  - `range` '24h' | '7d' | '30d', required
  - `days` UsageDay[], required: One row per model per UTC day with usage, oldest first. A day with no model call has no row. Under `project`, one row per UTC day with `model` and `provider` empty (a run's totals are not split by model), summed from the label's traced runs as `by_project` is.
    - `day` string, date, required
    - `model` string, required: The model id. Empty either when the span named only a provider, or, under a `project` filter, on every row, because each row is then a whole day of the project's runs across all models.
    - `provider` string, required: The provider (`gen_ai.system`). Empty either when the span named only a model, or, under a `project` filter, on every row (one row per day across all models).
    - `tokens_in` integer, required
    - `tokens_out` integer, required
    - `tokens_cache_read` integer, required
    - `tokens_cache_write` integer, required
    - `cost_usd` string, nullable, required: US dollars as decimal text; null when no call reported or could be priced.
    - `cost_source` string, required: What `cost_usd` is made of. A plain string, not an enum, so a new value never breaks a client. `client` when `cost_usd` is the tool's own figure: a metric-derived row's (Claude Code's cost metric, or Cursor's best-effort estimate); for one agent's usage, a trace-derived row whose day and model Claude Code's cost metric also covers (its figure replaces the traces' figure, which moves to `estimated_cost_usd`); or a trace-derived row whose every priced call carried a client-reported cost. `estimated` when LastPing priced every call at API list prices, `mixed` when a trace-derived row holds both kinds. The client figure and the traces' figure may describe different sets of calls (the metric covers every Claude Code call of the day, the traces only the traced ones). Empty when `cost_usd` is null.
    - `estimated_cost_usd` string, nullable, required: The traces' figure for the day and model when Claude Code's cost metric also covers them and its figure is `cost_usd`; null otherwise. The traces' figure is LastPing's estimate at API list prices, except for calls whose own client-reported cost was attached to them.
    - `origin` 'traces' | 'metrics', required: Where the row's numbers come from. `traces`: the span-derived daily aggregate. `metrics`: an OTLP metrics export, shown only for a day and model no span covered. The two are never added: a tool such as Claude Code sends spans and metrics for the same calls, so for one day, provider and model the trace-derived row wins. The project-wide usage report is trace-derived only.
  - `project` string, required: The `project` filter this response applied, after cleaning (a path reduced to its last element), or an empty string when there was none.
  - `project_scope` string, required: Where every figure that names a project comes from: `traces_only`. A project label rides a Claude Code hook's start ping, so only traced runs carry one; usage reported only through an OTLP metrics export has no project and is in no `by_project` row, nor in `days` under a `project` filter. A plain string, not an enum, so a new value never breaks a client.
  - `by_project` ProjectUsage[], required: Per project label, the usage of the label's traced runs over the range (see `ProjectUsage`), costliest first, at most 50. Runs with no label are in no row. Narrowed to one row by `project`. It need not sum to or match `days`: see `ProjectUsage`.
    - `project` string, required
    - `runs` integer, required: The label's traced runs whose start is in the range. A test run is not counted.
    - `tokens_in` integer, required
    - `tokens_out` integer, required
    - `tokens_cache_read` integer, required
    - `tokens_cache_write` integer, required
    - `cost_usd` string, nullable, required: US dollars as decimal text; null when no call reported or could be priced.
    - `cost_source` string, required: What `cost_usd` is made of, as `AgentUsage.cost_source`: `client` when every priced call's cost was reported by the client, `estimated` when LastPing priced every call at API list prices, `mixed` when the sum holds both, empty when `cost_usd` is null. A plain string, not an enum.

## Other responses

- `400`: An invalid `range` or `project` (`INVALID_FILTER`).
- `401`: Missing or invalid API key.
- `404`: Agent not found in this project (unknown UUID or slug).

---

[API](https://skmtc.dev/lastping/apis/lastping-management-api.md) · [All operations](https://skmtc.dev/lastping/apis/lastping-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lastping/apis/lastping-management-api/revisions/bbc6eda91c46?raw)
