Usage & Analytics API
The current hosted usage endpoints, filters, response envelopes, and server-only authentication model.
The hosted API records per-turn token and cost data. These endpoints are served
by @mordn/chat-api, not by your Next.js handler, and require a server-side
mordn API key.
curl "https://api.mordn.com/v1/usage/summary?view=production" \
-H "Authorization: Bearer $MORDN_CHAT_KEY"
Window and filters
The default window is the last 14 days. from is inclusive and to is
exclusive. Both are ISO timestamps. view is production, preview, or all
(the default).
Filters differ by endpoint:
| Endpoint | Additional filters |
|---|---|
summary |
userId, model, view |
timeseries |
`bucket=day |
by-model |
userId, view |
by-user |
limit, model, view |
top-conversations |
limit, `sort=cost |
unanswered |
optional consistency-check agentId |
Endpoints
GET /v1/usage/summary
{
"totals": {
"events": 12840,
"inputTokens": 8340221,
"outputTokens": 2114880,
"totalTokens": 10455101,
"cachedInputTokens": 512000,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": "42.1187",
"inputCostUsd": "30.0000",
"outputCostUsd": "12.1187",
"marketCostUsd": "40.0000",
"surchargeUsd": "2.1187"
}
}
GET /v1/usage/timeseries?bucket=day
{
"series": [
{
"ts": "2026-06-30T00:00:00.000Z",
"events": 502,
"inputTokens": 320000,
"outputTokens": 90233,
"totalTokens": 410233,
"costUsd": "1.6644"
}
]
}
GET /v1/usage/by-model
Returns { models: [{ model, events, totalTokens, costUsd }] } ordered by cost.
GET /v1/usage/by-user
Returns { users: [{ userId, events, totalTokens, costUsd }] }.
GET /v1/usage/top-conversations
Returns { conversations: [{ conversationId, events, totalTokens, costUsd }] }.
The aggregate does not include userId.
GET /v1/usage/unanswered
Returns recent retrieval misses grouped by normalized query:
{
"questions": [
{
"query": "How do I rotate a key?",
"count": 7,
"lastAskedAt": "2026-07-14T08:00:00.000Z",
"avgTopScore": 0.08
}
]
}
An optional agentId must match the key’s agent or the API returns 403.
Because this endpoint returns end-user query text, apply the same access and
retention controls as other analytics data.
Per-turn record
UsageRecord can also carry resolvedProvider, finish reason, step count,
latency, generation id, exact decimal cost strings, and
raw?: Record<string, unknown> provider metadata. Not every field is exposed by
every aggregate endpoint.
For a self-hosted backend, use onChatFinish or persist SaveTurnInput.usage
in your own store.