--- paperclip_version: v2026.720.0 seo_title: Costs API seo_description: Company-scoped endpoints for the four spend questions: what was spent, by whom, against which budget, and how close the company is to its cap. --- # Costs Use this API when you want to answer four questions: - How much did the company spend? - Which agents, models, providers, or projects are driving that spend? - Are budgets about to warn or hard-stop work? - What non-token financial events were recorded alongside token spend? All of these endpoints are company-scoped. --- ## Reporting Usage ### Cost events `POST /api/companies/{companyId}/cost-events` This is the main endpoint for token spend. Adapters typically call it after a heartbeat or other AI operation finishes. Required fields: - `agentId` - `provider` - `model` - `costCents` - `occurredAt` Common optional fields: - `issueId` when the spend came from a specific task - `projectId` when the spend clearly belongs to one project - `goalId` when you can attribute the spend higher up the tree - `heartbeatRunId` when the spend came from a specific run - `billingCode` for your own accounting label - `biller` if the charge came from a billing entity different from `provider` - `billingType` if you want to distinguish `metered_api`, `subscription_included`, `subscription_overage`, `credits`, `fixed`, or `unknown` - `costStatus` to mark whether the usage is priced — `reported` for normal spend, or `unpriced` when you recorded token usage but no dollar cost was available - `inputTokens`, `cachedInputTokens`, `outputTokens` for token-level reporting Rules from the implementation: - The agent must belong to the company. - Board users can report any company agent’s costs. - Agent-authenticated calls can only report that agent’s own costs. - `biller` defaults to `provider` when omitted. - `billingType` defaults to `unknown` when omitted. - `costStatus` defaults to `reported` when omitted. - `occurredAt` must be an ISO datetime string. > **Priced vs. unpriced usage.** Most cost events carry a real `costCents` amount, so they stay `reported`. When an agent run uses tokens but Paperclip can't determine a dollar cost — for example a local CLI whose per-token pricing isn't known — the usage is recorded with `costStatus` set to `unpriced` instead of being logged as if it cost nothing. That keeps the token counts on the record while flagging that the money figure is an unknown rather than a real zero. When the event is accepted, Paperclip: - stores the event - recalculates `spentMonthlyCents` for the agent and company - evaluates budget policies for soft warnings and hard stops - writes an activity log entry ```bash curl -X POST "http://localhost:3100/api/companies/company-1/cost-events" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "agentId": "agent-1", "issueId": "issue-1", "projectId": "project-1", "heartbeatRunId": "run-1", "provider": "anthropic", "biller": "anthropic", "billingType": "metered_api", "model": "claude-sonnet-4-20250514", "inputTokens": 15000, "cachedInputTokens": 2000, "outputTokens": 3000, "costCents": 12, "occurredAt": "2026-04-15T12:30:00.000Z" }' ``` ```js await fetch("http://localhost:3100/api/companies/company-1/cost-events", { method: "POST", headers: { Authorization: "Bearer ", "Content-Type": "application/json", }, body: JSON.stringify({ agentId: "agent-1", projectId: "project-1", heartbeatRunId: "run-1", provider: "anthropic", billingType: "metered_api", model: "claude-sonnet-4-20250514", inputTokens: 15000, cachedInputTokens: 2000, outputTokens: 3000, costCents: 12, occurredAt: "2026-04-15T12:30:00.000Z", }), }); ``` ```python import requests requests.post( "http://localhost:3100/api/companies/company-1/cost-events", headers={"Authorization": "Bearer "}, json={ "agentId": "agent-1", "projectId": "project-1", "heartbeatRunId": "run-1", "provider": "anthropic", "billingType": "metered_api", "model": "claude-sonnet-4-20250514", "inputTokens": 15000, "cachedInputTokens": 2000, "outputTokens": 3000, "costCents": 12, "occurredAt": "2026-04-15T12:30:00.000Z", }, ) ``` > **Tip:** If you already know the issue, project, or run that caused the spend, send those IDs. They make the breakdown views much more useful later. ### Cache-adjusted cost Prompt caching means the amount a provider actually bills for a run is often well below what its raw token counts imply. Paperclip records the billed amount rather than the nominal one, so the dollars in the ledger match the dollars on your invoice. Adapters express this through their execution result: - `costUsd` — the cost the adapter reports for the run, in US dollars. - `cacheAdjustedCostUsd` — the provider-billed cost after prompt-cache discounts, in US dollars. Adapters set this when they expose it separately from `costUsd`. Paperclip resolves the two into a single billed figure: - If `cacheAdjustedCostUsd` is a finite number that is zero or greater, that value is the billed cost. - Otherwise, if `costUsd` is a finite number that is zero or greater, that value is the billed cost — a provider-reported `costUsd` is treated as already cache-adjusted. - Otherwise there is no billed cost for the run. That resolved figure is what Paperclip converts into the `costCents` of the cost event it records for the run, so it is the number that flows into every summary, breakdown, and budget policy described below. It is also the figure used to decide `costStatus`: a run with token usage but no resolvable cost is recorded as `unpriced` rather than as a real zero. The run keeps both numbers. The heartbeat run's `usageJson` carries `costUsd` when the adapter reported one and `cacheAdjustedCostUsd` when a cache-adjusted amount was resolved, alongside the token counts and the `provider`, `biller`, `model`, `costStatus`, and `billingType` fields. Read them from either of: - `GET /api/companies/{companyId}/heartbeat-runs` - `GET /api/heartbeat-runs/{runId}` > **Note:** `cacheAdjustedCostUsd` and `costUsd` are in dollars, while `costCents` on cost events is in cents. Don't mix the two units when you reconcile a run against its ledger entry. --- ## Reading Spend ### Company summary `GET /api/companies/{companyId}/costs/summary` This returns the company’s total spend for the selected date range, the current company budget, and the utilization percentage. If you omit `from` and `to`, the service returns all-time totals. Query parameters: - `from` - optional ISO datetime - `to` - optional ISO datetime Response fields: - `spendCents` - `budgetCents` - `utilizationPercent` ```bash curl "http://localhost:3100/api/companies/company-1/costs/summary?from=2026-04-01T00:00:00.000Z&to=2026-04-30T23:59:59.999Z" \ -H "Authorization: Bearer " ``` ```js const res = await fetch( "http://localhost:3100/api/companies/company-1/costs/summary?from=2026-04-01T00:00:00.000Z&to=2026-04-30T23:59:59.999Z", { headers: { Authorization: "Bearer " } }, ); const summary = await res.json(); ``` ```python import requests summary = requests.get( "http://localhost:3100/api/companies/company-1/costs/summary", headers={"Authorization": "Bearer "}, params={ "from": "2026-04-01T00:00:00.000Z", "to": "2026-04-30T23:59:59.999Z", }, ).json() ``` ### Breakdown views These endpoints use the same optional `from` and `to` filters as the summary endpoint: - `GET /api/companies/{companyId}/costs/by-agent` - `GET /api/companies/{companyId}/costs/by-agent-model` - `GET /api/companies/{companyId}/costs/by-provider` - `GET /api/companies/{companyId}/costs/by-biller` - `GET /api/companies/{companyId}/costs/by-project` What each one is for: - `by-agent` helps you find which employees are expensive overall. - `by-agent-model` helps you spot a specific agent/model combination that is burning tokens. - `by-provider` helps you compare Anthropic, OpenAI, and any other provider you ingest. - `by-biller` helps when the provider name and the billable entity are not the same. - `by-project` helps you connect cost back to project work rather than just an agent. ### Fast moving spend `GET /api/companies/{companyId}/costs/window-spend` This returns rolling spend for the last `5h`, `24h`, and `7d`. It is useful for spotting sudden spikes without having to choose a date range yourself. --- ## Budget Controls ### Set company budget `PATCH /api/companies/{companyId}/budgets` This is the simplest way to set the monthly company budget. The implementation also syncs a matching company budget policy behind the scenes. ### Set agent budget `PATCH /api/agents/{agentId}/budgets` This sets the monthly budget for a specific agent and also syncs the corresponding agent budget policy. The request body for both endpoints is the same: ```json { "budgetMonthlyCents": 5000 } ``` The budget window is calendar-month UTC for company and agent monthly budgets. ```bash curl -X PATCH "http://localhost:3100/api/companies/company-1/budgets" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "budgetMonthlyCents": 100000 }' ``` ```js await fetch("http://localhost:3100/api/companies/company-1/budgets", { method: "PATCH", headers: { Authorization: "Bearer ", "Content-Type": "application/json", }, body: JSON.stringify({ budgetMonthlyCents: 100000 }), }); ``` ```python import requests requests.patch( "http://localhost:3100/api/companies/company-1/budgets", headers={"Authorization": "Bearer "}, json={"budgetMonthlyCents": 100000}, ) ``` ### Budget overview `GET /api/companies/{companyId}/budgets/overview` Use this when you want the board-level view of budget health. It returns: - the current policies - active incidents - paused agent and project counts - pending approval count ### Policy upsert `POST /api/companies/{companyId}/budgets/policies` This is the general budget policy API. Use it when you need a policy for a company, agent, or project rather than just a monthly company budget. Important defaults from the implementation: - `metric` defaults to `billed_cents` - `windowKind` defaults to `calendar_month_utc` for company and agent scopes - `windowKind` defaults to `lifetime` for project scopes - `warnPercent` defaults to `80` - `hardStopEnabled` defaults to `true` - `notifyEnabled` defaults to `true` - `isActive` defaults to `true` ### Budget incidents `POST /api/companies/{companyId}/budget-incidents/{incidentId}/resolve` Allowed actions: - `keep_paused` - `raise_budget_and_resume` If you raise the budget, you must supply a new `amount` that exceeds the current observed spend. > **Warning:** Hard-stop budget enforcement pauses the affected scope and cancels work for that scope. A budget increase only resumes the scope if the new budget is above current observed spend. ### What happens at the thresholds - At the warn threshold, the service creates a soft incident when notifications are enabled. - At 100 percent, the service creates a hard incident when hard-stop is enabled. - Hard-stop policies pause the affected company, agent, or project and cancel work for that scope. - Budget windows reset on the first day of each month in UTC. - Project policies default to lifetime windows unless you choose a different window kind explicitly. --- ## Finance Events These endpoints track non-token accounting events alongside cost events. They are useful for credits, refunds, platform fees, manual adjustments, and other finance records that are not raw token usage. ### Create finance event `POST /api/companies/{companyId}/finance-events` This endpoint is board-only. ### Read finance data - `GET /api/companies/{companyId}/costs/finance-summary` - `GET /api/companies/{companyId}/costs/finance-by-biller` - `GET /api/companies/{companyId}/costs/finance-by-kind` - `GET /api/companies/{companyId}/costs/finance-events` The finance list endpoint supports: - `from` - `to` - `limit` from `1` to `500` with a default of `100` Useful event kinds include things like `inference_charge`, `platform_fee`, `credit_purchase`, `credit_refund`, and `manual_adjustment`. The API also stores `direction`, `amountCents`, `currency`, `estimated`, and optional metadata. --- ## Internal Diagnostics `GET /api/companies/{companyId}/costs/quota-windows` This is a board-only diagnostic endpoint. It returns quota window information used by the system to understand provider usage windows. The company must exist and the caller must be board-authenticated. --- ## Practical Reading Order If you are trying to understand a company’s spending, start here: 1. `GET /costs/summary` 2. `GET /costs/by-agent` 3. `GET /costs/by-project` 4. `GET /budgets/overview` 5. `GET /costs/window-spend` That sequence usually tells you whether the problem is a single agent, a single project, a provider mix issue, or a real budget policy problem.