Skip to main content
Paymaster exposes read-only cost rollups across crew, agent, and mission scopes, plus a leaderboard of top spenders and a flat-rate subscription usage view. Every spend figure comes from the cost_ledger, which is written exclusively by the internal cost-record path — there are no public write endpoints. See the Paymaster guide for the cost ledger and budget model, and the Sidecar coverage section for the known limitation around agent CLI bypass.
All read endpoints require authentication and are workspace-scoped. The write path is exclusively internal via the LLM middleware — there are no POST endpoints on the public surface.

Endpoints

MethodEndpointPurpose
GET/api/v1/paymaster/spend/by-crewCost rollup grouped by crew
GET/api/v1/paymaster/spend/by-agent/{crewId}Cost rollup by agent within a crew
GET/api/v1/paymaster/spend/by-mission/{missionId}Total spend for one mission
GET/api/v1/paymaster/top-spendersLeaderboard of agents by spend
GET/api/v1/paymaster/subscriptionsFlat-rate credential usage rollup
POST/api/v1/internal/cost/recordInternal: sidecar reports parsed LLM usage

Time window parameters

Every endpoint accepts the same window parameters:
ParamTypeDescription
rangestringOne of 1h, 24h, 7d, 30d. Default 7d.
sincestringExplicit RFC3339 lower bound. Overrides range when set.
untilstringExplicit RFC3339 upper bound. Defaults to now.

Spend by crew

GET /api/v1/paymaster/spend/by-crew?range=7d
Response: 200 OK
{
  "rows": [
    {
      "crew_id": "crw_backend",
      "cost_usd": 14.3210,
      "call_count": 132,
      "input_tokens": 1024583,
      "output_tokens": 457758
    }
  ],
  "since": "2026-04-10T10:00:00Z",
  "until": "2026-04-17T10:00:00Z"
}
FieldTypeDescription
rows[].crew_idstringCrew identifier.
rows[].cost_usdnumberSum of cost_ledger.cost_usd for the crew in the window.
rows[].call_countintegerNumber of LLM calls.
rows[].input_tokensintegerSum of input_tokens.
rows[].output_tokensintegerSum of output_tokens.
Errors: 401 no workspace; 500 DB error.

Spend by agent (within a crew)

GET /api/v1/paymaster/spend/by-agent/{crewId}?range=24h
Path parameters:
ParamDescription
crewIdCrew ID. Must belong to the caller’s workspace.
Response: 200 OK
{
  "crew_id": "crw_backend",
  "rows": [
    {
      "agent_id": "agt_viktor",
      "cost_usd": 4.2103,
      "call_count": 42,
      "input_tokens": 158421,
      "output_tokens": 73119
    }
  ]
}
Errors:
StatusCondition
400Missing crewId.
401No workspace.
404crewId not in your workspace (same shape as “not found”).
500DB error.

Spend by mission

GET /api/v1/paymaster/spend/by-mission/{missionId}
Mission-scoped spend. Window-less — sums the full mission. Response: 200 OK
{
  "mission_id": "MIS-42",
  "row": {
    "mission_id": "MIS-42",
    "cost_usd": 7.8945,
    "call_count": 28,
    "input_tokens": 542108,
    "output_tokens": 192743,
    "first_ts": "2026-04-10T10:14:02Z",
    "last_ts": "2026-04-17T09:58:31Z"
  }
}
first_ts / last_ts span the activity window for the mission. When no spend has been recorded they come back as the zero time ("0001-01-01T00:00:00Z"); the other numeric fields are 0. Errors:
StatusCondition
400Missing missionId.
404missionId not in your workspace.

Top spenders

GET /api/v1/paymaster/top-spenders?limit=10&range=7d
Query parameters:
ParamTypeDefaultDescription
limitinteger101-100.
range / since / until7dWindow.
Response: 200 OK
{
  "rows": [
    {
      "scope_kind": "agent",
      "scope_id": "agt_viktor",
      "cost_usd": 14.3210,
      "call_count": 132
    },
    {
      "scope_kind": "agent",
      "scope_id": "agt_eva",
      "cost_usd": 4.2103,
      "call_count": 42
    }
  ],
  "limit": 10,
  "since": "2026-04-10T10:00:00Z"
}
FieldTypeDescription
rows[].scope_kindstringAlways agent — the leaderboard ranks agents by spend (rows with a NULL agent_id are excluded).
rows[].scope_idstringThe agent ID.

Subscriptions

GET /api/v1/paymaster/subscriptions?range=30d
Rollup of flat-rate credential usage grouped by (subscription_plan, provider). Returned rows carry call counts and token totals only — no $ figure. The subscription is a flat fee paid up front, so the marginal token cost is structurally $0; rendering “$0.00” would imply the calls are free, which they are not. Query parameters:
ParamTypeDefaultDescription
range / since / until30dTime window. Same semantics as the spend/* endpoints.
Response: 200 OK
{
  "rows": [
    {
      "subscription_plan": "Anthropic Max 20×",
      "provider": "anthropic",
      "call_count": 1284,
      "input_tokens": 14_205_338,
      "output_tokens": 5_127_912,
      "last_ts": "2026-04-30T11:42:18.221Z"
    },
    {
      "subscription_plan": "ChatGPT Plus",
      "provider": "openai",
      "call_count": 312,
      "input_tokens": 1_802_443,
      "output_tokens": 622_501,
      "last_ts": "2026-04-30T09:11:02.083Z"
    }
  ],
  "since": "2026-03-31T11:42:18Z",
  "until": "2026-04-30T11:42:18Z"
}
FieldTypeDescription
rows[].subscription_planstringDisplay label set by the orchestrator from the credential type (e.g. "Anthropic Max 20×").
rows[].providerstringLLM provider (anthropic, openai, …).
rows[].call_countintegerNumber of cost_ledger rows with billing_mode='flat_rate' for this (plan, provider).
rows[].input_tokensintegerSum of input_tokens.
rows[].output_tokensintegerSum of output_tokens.
rows[].last_tsstring (RFC3339)Most recent ts in the group.
Errors: 401 no workspace; 500 DB error.

Internal: cost record

POST /api/v1/internal/cost/record
Internal only — X-Internal-Token required. This is how the sidecar reports parsed LLM usage from inside a crew container. Agents cannot reach this endpoint directly; the sidecar runs as UID 1002 and holds the token. Authoritative scope (workspace / crew / agent IDs) is taken from the sidecar’s IPCConfig set at exec time, so an agent that captures the token still cannot forge cross-tenant attribution.
See Internal IPC API for the full request/response schema and the surrounding security model.