Usage tracking API
The usage tracking system records per-event token consumption and tool execution metrics. You can query aggregated data by agent, model, or time period.
The usage tracker records events to a PostgreSQL database whenever an AI completion or tool call is made. The endpoints below are read-only query APIs for retrieving aggregated usage data. When no real usage data exists yet, the cost dashboard returns sample data with a isMockData: true flag.
Test usage logging (deprecated)
This endpoint was removed in the March 2026 security audit and is no longer available. Requests to this path return
404. Use the
cost dashboard endpoint to verify that usage tracking is working.
A debug endpoint that fires a single test event through the usage logging pipeline.
Cost dashboard
Returns aggregated cost, token, and call data for the cost dashboard. Breaks down spending by agent, model, and day. Requires session authentication.
When no usage data is available, the endpoint returns realistic sample data with isMockData set to true and a message field explaining that usage tracking is not yet configured.
Query parameters
| Parameter | Type | Default | Description |
|---|
period | string | 7d | Time window for the aggregation. Accepted values: 7d (last 7 days), 30d (last 30 days), mtd (month to date). |
Response
{
"period": "7d",
"summary": {
"totalCost": 13.68,
"totalTokens": 4560000,
"totalCalls": 1946,
"avgCostPerCall": 0.007
},
"agents": [
{
"name": "Atlas",
"tokens": 2840000,
"cost": 8.52,
"calls": 1247,
"avgCostPerCall": 0.0068,
"model": "claude-3-7-sonnet"
}
],
"daily": [
{
"date": "Mar 17",
"cost": 1.42,
"tokens": 380000
}
],
"modelBreakdown": [
{
"model": "claude-3-7-sonnet",
"percent": 68,
"cost": 9.30
}
],
"isMockData": false
}
Response fields
| Field | Type | Description |
|---|
period | string | The requested period echoed back (7d, 30d, or mtd) |
summary.totalCost | number | Total cost in USD for the period |
summary.totalTokens | number | Total tokens (input + output) consumed |
summary.totalCalls | number | Total API calls made |
summary.avgCostPerCall | number | Blended average cost per call in USD |
agents | array | Per-agent cost breakdown, sorted by cost descending |
agents[].name | string | Agent name or identifier |
agents[].tokens | number | Total tokens consumed by the agent |
agents[].cost | number | Total cost in USD attributed to the agent |
agents[].calls | number | Number of API calls made by the agent |
agents[].avgCostPerCall | number | Average cost per call for the agent |
agents[].model | string | Primary model used by the agent |
daily | array | Daily cost and token totals |
daily[].date | string | Formatted date label (e.g. "Mar 17") |
daily[].cost | number | Cost in USD for that day |
daily[].tokens | number | Total tokens consumed that day |
modelBreakdown | array | Cost breakdown by model, sorted by cost descending |
modelBreakdown[].model | string | Model identifier |
modelBreakdown[].percent | number | Percentage of total cost attributed to this model |
modelBreakdown[].cost | number | Cost in USD for this model |
isMockData | boolean | true when the response contains sample data because no real usage data is available |
message | string | undefined | Present only when isMockData is true. Explains that sample data is being returned. |
Errors
| Code | Description |
|---|
| 500 | Failed to fetch cost data |
The remaining endpoints on this page are planned for a future release. They are not yet available. Usage events are recorded internally but these query APIs have not been deployed. This section documents the intended specification for reference.
All query endpoints below require bearer token authentication and are served by the backend API.
Usage summary
Returns daily aggregated token usage and cost data across all agents and models.
Query parameters
| Parameter | Type | Default | Description |
|---|
days | integer | 30 | Number of days of history to return |
Response
[
{
"date": "2026-03-22",
"agent_id": "agent_abc",
"model": "openrouter/anthropic/claude-sonnet-4",
"provider": "openrouter",
"input_tokens": 15200,
"output_tokens": 3400,
"total_tokens": 18600,
"cost_usd": 0.042,
"turn_count": 12
}
]
Response fields
| Field | Type | Description |
|---|
date | string | Date in YYYY-MM-DD format |
agent_id | string | null | Agent that generated the usage, or null for unattributed events |
model | string | Model identifier |
provider | string | AI provider name |
input_tokens | number | Total input tokens for the day |
output_tokens | number | Total output tokens for the day |
total_tokens | number | Sum of all token types (input, output, cache read, cache write) |
cost_usd | number | Estimated cost in USD |
turn_count | number | Number of individual completion calls |
Usage by agent
GET /api/usage/by-agent/:agentId
Returns token usage grouped by model for a specific agent.
Path parameters
| Parameter | Type | Description |
|---|
agentId | string | ID of the agent to query |
Query parameters
| Parameter | Type | Default | Description |
|---|
days | integer | 30 | Number of days of history to include |
Response
[
{
"model": "openrouter/anthropic/claude-sonnet-4",
"provider": "openrouter",
"input_tokens": 45000,
"output_tokens": 12000,
"total_tokens": 57000,
"cost_usd": 0.13,
"events": 48
}
]
Response fields
| Field | Type | Description |
|---|
model | string | Model identifier |
provider | string | AI provider name |
input_tokens | number | Total input tokens |
output_tokens | number | Total output tokens |
total_tokens | number | Total tokens across all types |
cost_usd | number | Estimated cost in USD |
events | number | Number of usage events |
Usage by model
Returns token usage aggregated by model across all agents.
Query parameters
| Parameter | Type | Default | Description |
|---|
days | integer | 30 | Number of days of history to include |
Response
[
{
"model": "openrouter/anthropic/claude-sonnet-4",
"provider": "openrouter",
"input_tokens": 120000,
"output_tokens": 35000,
"total_tokens": 155000,
"cost_usd": 0.35,
"turns": 200
}
]
Response fields
| Field | Type | Description |
|---|
model | string | Model identifier |
provider | string | AI provider name |
input_tokens | number | Total input tokens |
output_tokens | number | Total output tokens |
total_tokens | number | Total tokens across all types |
cost_usd | number | Estimated cost in USD |
turns | number | Total completion turns |
Daily totals
Returns total token usage and cost per day.
Query parameters
| Parameter | Type | Default | Description |
|---|
days | integer | 7 | Number of days of history to return |
Response
[
{
"date": "2026-03-22",
"total_tokens": 85000,
"cost_usd": 0.19,
"turns": 72
},
{
"date": "2026-03-21",
"total_tokens": 62000,
"cost_usd": 0.14,
"turns": 55
}
]
Response fields
| Field | Type | Description |
|---|
date | string | Date in YYYY-MM-DD format |
total_tokens | number | Total tokens used that day |
cost_usd | number | Estimated cost in USD |
turns | number | Total completion turns |
Returns aggregated tool execution statistics, optionally filtered by agent.
Query parameters
| Parameter | Type | Default | Description |
|---|
agentId | string | — | Filter results to a specific agent. Omit for all agents. |
days | integer | 7 | Number of days of history to include |
Response
[
{
"tool_name": "web_search",
"calls": 150,
"successes": 142,
"avg_ms": 1230.5
},
{
"tool_name": "code_edit",
"calls": 85,
"successes": 83,
"avg_ms": 450.2
}
]
Response fields
| Field | Type | Description |
|---|
tool_name | string | Name of the tool |
calls | number | Total number of invocations |
successes | number | Number of successful invocations |
avg_ms | number | Average execution duration in milliseconds |
Usage event schema
Each usage event is stored as a row in the usage_logs table (Prisma model name: UsageLog). Events are recorded automatically whenever an AI completion is made (for example, from the demo chat endpoint or agent chat). Cost is calculated at write time using per-model pricing rates.
The usage_logs table is created via a dedicated SQL migration (20260323000000_add_usage_logs) rather than through Prisma’s schema push. This ensures the table is created reliably across deployments without requiring Prisma to manage the migration state.
Server-side logging
Every usage event emits a structured log line to the server console when it is recorded. This makes it possible to verify that the usage tracking pipeline is working without querying the database.
Success log format:
[UsageLogger] Logging: <agentId> | <model> | <inputTokens>+<outputTokens> tokens | $<cost>
For example:
[UsageLogger] Logging: demo-chat | gpt-4o | 450+120 tokens | $0.004050
If the database write fails, an error is logged instead:
[UsageLogger] Failed to log usage: <error message>
Because usage recording is fire-and-forget (it never blocks the API response), these log lines are the primary way to diagnose write failures. Monitor your server logs for [UsageLogger] Failed to log usage entries if usage data appears to be missing from the cost dashboard.
Cost dashboard logging
The cost dashboard endpoint emits its own diagnostic log lines prefixed with [Cost API]. These help you verify that the aggregation query is running and returning data.
Query result log:
[Cost API] Found <count> usage logs
For example:
[Cost API] Found 42 usage logs
If the Prisma query fails, the endpoint logs the error and falls back to sample data:
[Cost API] Prisma error: <error message>
If the entire handler fails, a general error is logged and a 500 response is returned:
[Cost API] Error: <error message>
| Field | Type | Description |
|---|
id | integer | Auto-incrementing primary key |
user_id | varchar(255) | User who triggered the event |
agent_id | varchar(255) | Agent that triggered the completion |
model | varchar(100) | Model identifier (for example anthropic/claude-sonnet-4.5) |
input_tokens | integer | Number of input (prompt) tokens. Defaults to 0. |
output_tokens | integer | Number of output (completion) tokens. Defaults to 0. |
cost_usd | decimal(10,6) | Computed cost in USD (six decimal places). Defaults to 0. |
endpoint | varchar(255) | null | API route that generated the event (for example /api/demo/chat) |
latency_ms | integer | null | Response latency in milliseconds |
success | boolean | Whether the completion succeeded. Defaults to true. |
error_message | text | null | Error description when success is false |
created_at | timestamp | Timestamp when the event was recorded. Defaults to NOW(). |
When accessing the table through the Prisma ORM, use the camelCase field names (userId, agentId, inputTokens, etc.). When writing raw SQL queries, use the snake_case column names shown above (user_id, agent_id, input_tokens, etc.).
The table is indexed on user_id, agent_id, created_at, and the composite pairs (user_id, created_at) and (agent_id, created_at) for efficient time-range queries.
The usage event schema was updated in the March 2026 release. The previous fields session_id, session_key, cache_read_tokens, cache_write_tokens, and total_tokens are no longer recorded. Use input_tokens + output_tokens to calculate total tokens.
Each tool event records:
| Field | Type | Description |
|---|
session_id | string | null | Session that triggered the tool call |
agent_id | string | null | Agent that invoked the tool |
tool_name | string | Name of the tool |
success | boolean | Whether the tool call succeeded |
duration_ms | number | null | Execution time in milliseconds |
Errors
All usage tracking endpoints return the following error codes:
| Code | Description |
|---|
| 401 | Unauthorized — missing or invalid bearer token |
| 500 | Database query failed |