Skip to main content

API

Dashboard endpoints live under /api/* and require a signed-in account unless accounts are off (COSTPILOT_AUTH=off or demo mode). Admin endpoints under /api/admin/* need the admin role. Ingestion and the agent config live under /v1/* and are protected by COSTPILOT_INGEST_TOKEN. /health is always open.

Dashboard​

EndpointPurpose
GET /api/summary?from&to&filter=dim=valueKPIs (incl. turns and turnCostUsd, the spend of calls that belong to a turn), previous-period delta, cost per day (per hour for ranges up to two days), productivity
GET /api/breakdown?by=<dim>&…Cost per dimension value (project, issue, actor, actor_type, provider, model, source, repo, session, turn or any metadata key); rows carry sessions, turns and turnCostUsd, actorType (human/agent) for by=actor, and startedAt for by=session and by=turn. The older user dimension still works
GET /api/timeseries?by=<dim>&…Cost per day, stacked (top 6 + Other, flagged other: true); per hour for ranges up to two days (bucket field). by defaults to model
GET /api/records?limit&offset&…Individual calls (activity feed); limit defaults to 50, max 500
GET /api/activity?tz&…Active time per day (from claude_code.active_time.total) and a weekday × hour punchcard of LLM calls; tz = minutes as JS getTimezoneOffset() reports
GET /api/tools?from&toTool usage (calls, errors, avg. duration) incl. MCP server rollup, from the tools' tool-result events (Claude Code, Gemini CLI, Codex CLI); Claude Code MCP server names require OTEL_LOG_TOOL_DETAILS=1
GET /api/alerts · POST /api/alerts · DELETE /api/alerts/:idBudget alerts: threshold per scope (total or dimension+value) over a rolling window (7/30/90 days); status ok/warning (from 80 %)/breached is computed live. Admin only for writes
GET /api/analysis/issues?from&to&project&calcAnalysis tab: every issue with spend in the range (in project, or all projects incl. issues without one) with cost, turns and the spend that arose in turns; calc=whole (default) counts everything ever recorded for an issue, calc=range only the range. Plus the group sums and the spend without an issue
GET /api/dimensions · GET /api/metaDimension list, app info (version, demo flag, branding, record count and data range)

Date ranges and filters​

from/to take ISO datetimes or YYYY-MM-DD (UTC day; to is exclusive, a bare date means end of that day). The dashboard maps its presets (today, 7/30/90 days, this/last month, all time) and the custom picker onto these.

Filters are repeatable:

GET /api/breakdown?by=model&filter=issue=FC-101&filter=actor=alice

An empty value (filter=issue=) selects the "none" bucket.

Budget alert body​

{
"name": "Platform squad, monthly",
"dimension": "project",
"value": "PLAT",
"thresholdUsd": 1500,
"days": 30
}

dimension and value are optional; without them the alert covers total spend. days is 7, 30 or 90.

Accounts​

EndpointPurpose
GET /api/sessionPublic: whether accounts are on, whether first-run setup is pending, and the signed-in user
POST /api/setupPublic, once: creates the first admin (needs the setup code from the server log)
GET /api/invites/:token · POST /api/invites/:token/acceptPublic: invite details; accepting creates the account and signs it in
/api/auth/*Better Auth: sign-in/out, password change, user management (/api/auth/admin/*)

Admin​

EndpointPurpose
GET /api/admin/projects · POST /api/admin/projects · PUT /api/admin/projects/:idProject registry (name, key, issue key pattern, repositories); 409 when a key or repository is taken
GET /api/admin/agent-settings · PUT /api/admin/agent-settingsCentral agent setup (tools, logToolDetails, default issue key pattern)
PUT /api/admin/brandingInstance branding { name?, color?: "#rrggbb", logo?: data URL } (png/jpeg/webp/svg up to ~256 KB); empty fields reset to default; 403 in demo mode
GET /api/admin/invites · POST /api/admin/invites · DELETE /api/admin/invites/:idPending invites; POST returns the single-use link path

Ingestion and agent​

EndpointPurpose
POST /v1/logsOTLP logs (Claude Code api_request and tool events, Gemini CLI, Codex CLI)
POST /v1/metricsOTLP metrics (productivity counters; cumulative payloads are diffed)
POST /v1/tracesAccepted and discarded, so exporters do not log errors
POST /v1/session-mapPrompt and turn-end reports from the agent hook, see Wire contract
GET /v1/agent-configCentral agent config: setup, all projects with pattern and repositories, defaultIssueKeyPattern, turnEndReports: true
GET /v1/projects/:projectKeyA single project in the same shape; 404 for an unknown key

OTLP payloads are JSON (OTEL_EXPORTER_OTLP_PROTOCOL=http/json), optionally gzip-encoded. The ingestion is wire-compatible with the FeatureCost PoC receiver, so existing telemetry setups keep working unchanged.

Health​

GET /health returns 200 and is excluded from auth, for platform healthchecks.