Assert the Principal
Your backend authenticates its own users and asserts the Principal when it calls Checkfu. Checkfu API keys stay server-side and are never exposed to an end user.CHECKFU_API_KEY, CHECKFU_WORKSPACE_ID, CHECKFU_AGENT_ID, and CHECKFU_PRINCIPAL_ID come from Get access and the Agent you published. The TypeScript tabs below use the TypeScript SDK with this client:
Read the ledger
GET /v1/usage returns one row per immutable billing fact. Use it when you need exact source rows or Principal, Agent, Session, and Run filters.
principal_id, agent_id, surface_scope_id, automation_id, session_id, or run, and order with order=asc|desc. Page with the opaque next_page cursor.
Each row carries exactly one measurement dimension:
total_tokens is authoritative. Do not rebuild it from message text or traces. Cached and reasoning tokens are not visible there, and the ledger is the billing record.
Harness-build compute is not in this ledger and not on this API. A HarnessBuild has no Session, Run, or RunAttempt to anchor a
UsageEntry to, so its compute is metered in a separate build-usage ledger keyed by build and attempt, and the two join only at billing. That means these rows are a complete record of agent execution and not of every billable minute — do not reconcile an invoice against them alone. Budgets see the same boundary: a Budget bounds agent execution under a principal-scoped lineage, and a build has none, so builds are bounded by admission limits instead of by your Budget.Every row has exactly one of
principal_id or anonymous_subject_ref. After a Principal is erased under a data-deletion request, principal_id goes null while the accounting fact survives. Aggregations must tolerate that, or a deletion will silently change historical totals.Read daily usage and known spend
GET /v1/usage/series returns server-owned Workspace totals in aligned UTC-day buckets. The range is inclusive at from, exclusive at to, and may span at most 90 days. bucket=day is the only bucket, and an IANA display timezone is required; the timezone is echoed for presentation and never moves facts between canonical UTC buckets.
group_by takes none (Workspace totals) or exactly one attribution dimension — agent_definition, model_routing_profile, cost_class, or automation. One dimension, never a cube: two dimensions at once is not a supported read. A grouped read carries no latency guarantee, while group_by=none keeps the measured one, so reach for a dimension when you need the breakdown rather than by default.
exact_picousd; it is never inferred from catalog pricing. Choose event_time to place corrections with the original work, or accounting_time to place each monetary fact when it was recorded.
Treat watermark.status: partial, incomplete: true, or spend_status: partial as known spend, not total spend. byok, unpriced, and unknown coverage are not zero. The route fails closed when no verified projection exists and never falls back to an unbounded client-side sum.
Cap spend per user
A Budget scoped to a Principal enforces a ceiling without any work on your side:breach_action values block new admission once the ceiling is reached. The setting decides only whether a turn already in flight is additionally interrupted. block_admission leaves the running turn alone; interrupt_turn stops it.
When a hard threshold blocks a request you receive 429 budget.exceeded. That error also covers Workspace quotas, ToolInvocation ceilings, and API-key rate limits, so surface it to your user as “limit reached” rather than assuming which limit it was.
Set metric to model_spend to express both thresholds in integer micro-USD instead. Checkfu converts normalized token dimensions with its reviewed, effective-dated price catalog; provider-reported money is reconciliation evidence only. Attaching the Budget fails with the unpriced provider/model named when any admitted candidate lacks catalog coverage, and the actual candidate set is checked again before every provider call. session_runtime_ms caps closed running intervals. total_spend caps invoice micro-USD (session runtime plus platform-supply model charges).
Separating your limits from Checkfu’s
Four independent gates can each refuse work, and none substitutes for another:
All applicable gates must allow a request. Distinguish them in your UI: the first is your own policy and you can raise it, the middle two need action from an Organization administrator, and the last clears on its own (or permanently, by bringing your own key).
Next steps
Automations and operations
The full Budget and Usage shapes.
Tenancy and governance
How Principals relate to Workspaces and PermissionAssignments.