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:
agentIdprovidermodelcostCentsoccurredAt
Common optional fields:
issueIdwhen the spend came from a specific taskprojectIdwhen the spend clearly belongs to one projectgoalIdwhen you can attribute the spend higher up the treeheartbeatRunIdwhen the spend came from a specific runbillingCodefor your own accounting labelbillerif the charge came from a billing entity different fromproviderbillingTypeif you want to distinguishmetered_api,subscription_included,subscription_overage,credits,fixed, orunknowncostStatusto mark whether the usage is priced —reportedfor normal spend, orunpricedwhen you recorded token usage but no dollar cost was availableinputTokens,cachedInputTokens,outputTokensfor 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.
billerdefaults toproviderwhen omitted.billingTypedefaults tounknownwhen omitted.costStatusdefaults toreportedwhen omitted.occurredAtmust be an ISO datetime string.
Priced vs. unpriced usage. Most cost events carry a real
costCentsamount, so they stayreported. 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 withcostStatusset tounpricedinstead 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
spentMonthlyCentsfor the agent and company - evaluates budget policies for soft warnings and hard stops
- writes an activity log entry
curl -X POST "http://localhost:3100/api/companies/company-1/cost-events" \
-H "Authorization: Bearer <token>" \
-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"
}'
await fetch("http://localhost:3100/api/companies/company-1/cost-events", {
method: "POST",
headers: {
Authorization: "Bearer <token>",
"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",
}),
});
import requests
requests.post(
"http://localhost:3100/api/companies/company-1/cost-events",
headers={"Authorization": "Bearer <token>"},
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.
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 datetimeto- optional ISO datetime
Response fields:
spendCentsbudgetCentsutilizationPercent
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 <token>"
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 <token>" } },
);
const summary = await res.json();
import requests
summary = requests.get(
"http://localhost:3100/api/companies/company-1/costs/summary",
headers={"Authorization": "Bearer <token>"},
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-agentGET /api/companies/{companyId}/costs/by-agent-modelGET /api/companies/{companyId}/costs/by-providerGET /api/companies/{companyId}/costs/by-billerGET /api/companies/{companyId}/costs/by-project
What each one is for:
by-agenthelps you find which employees are expensive overall.by-agent-modelhelps you spot a specific agent/model combination that is burning tokens.by-providerhelps you compare Anthropic, OpenAI, and any other provider you ingest.by-billerhelps when the provider name and the billable entity are not the same.by-projecthelps 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:
{ "budgetMonthlyCents": 5000 }
The budget window is calendar-month UTC for company and agent monthly budgets.
curl -X PATCH "http://localhost:3100/api/companies/company-1/budgets" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{ "budgetMonthlyCents": 100000 }'
await fetch("http://localhost:3100/api/companies/company-1/budgets", {
method: "PATCH",
headers: {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
},
body: JSON.stringify({ budgetMonthlyCents: 100000 }),
});
import requests
requests.patch(
"http://localhost:3100/api/companies/company-1/budgets",
headers={"Authorization": "Bearer <token>"},
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:
metricdefaults tobilled_centswindowKinddefaults tocalendar_month_utcfor company and agent scopeswindowKinddefaults tolifetimefor project scopeswarnPercentdefaults to80hardStopEnableddefaults totruenotifyEnableddefaults totrueisActivedefaults totrue
Budget incidents
POST /api/companies/{companyId}/budget-incidents/{incidentId}/resolve
Allowed actions:
keep_pausedraise_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-summaryGET /api/companies/{companyId}/costs/finance-by-billerGET /api/companies/{companyId}/costs/finance-by-kindGET /api/companies/{companyId}/costs/finance-events
The finance list endpoint supports:
fromtolimitfrom1to500with a default of100
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:
GET /costs/summaryGET /costs/by-agentGET /costs/by-projectGET /budgets/overviewGET /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.