Skip to main content
Billing is real US dollars held as a credit balance on the organization. Every metered action debits the balance; top-ups credit it. All money fields are integer micro-USD (*_micro_usd, where 1 USD = 1,000,000 micro-USD).

Balance

GET /v1/credits/balance returns the current balance.
string
Always credit_balance.
integer
Available balance, in micro-USD.
string
live or test — the tier this balance is held in.

Ledger

GET /v1/credits/ledger lists metered entries, newest first. Cursor-paginated — see Pagination. Each inference debit carries a 5-tier token line-item breakdown of what was metered.
object[]
Ledger entries.
Filter the ledger with any combination of ?type=, ?session_id=, ?agent_id=, ?deployment_id=, ?from=, and ?to= (the from/to bounds are RFC 3339 timestamps).
Response

Top up

POST /v1/credits/topups opens a hosted charge and returns a topup object describing it. It does not move the balance: credit is applied when the payment provider’s signed callback arrives and is verified, so poll the balance rather than reading the create response as settlement. Requires the billing:write scope.
integer
required
Amount to add, in micro-USD.

The topup object

string
Top-up id (e.g. top_01H...).
integer
Amount requested, in micro-USD.
string
Lifecycle state. One of:
  • pending — the charge is being processed.
  • requires_action — the payment needs additional authentication (e.g. 3-D Secure). Complete it via action_url, then poll.
  • succeeded — the charge cleared and the balance was credited.
  • failed — the charge was declined; the balance is unchanged.
string | null
Present only when status is requires_action: the URL to complete authentication.
integer | null
Always null on this response — the balance moves only when the provider callback settles the charge. Read the balance instead.
string
Creation timestamp.
Response

Confirming a charge that is not yet terminal

A charge can land in pending or requires_action, so the status on the create response is not always the final word.
There is no GET /v1/credits/topups/{id}. A top-up is not individually addressable — that route is not served and answers 404 not_found. Confirm a charge by re-reading the balance or the ledger, not by polling a top-up id.
Two ways to reach the terminal state:
  • Poll the balance. GET /v1/credits/balance reflects the credit as soon as the charge clears. This is the simplest check when you know the amount you expect.
  • Read the ledger. GET /v1/credits/ledger lists entries newest-first; the settled top-up appears as a credit entry. Match it by created_at and amount_micro_usd.
When status comes back requires_action, send the payer to action_url first; the balance does not move until they complete authentication.
When the balance is too low to cover a call, the API returns insufficient_credits (402); when a call would breach a configured per-agent or per-session cap it returns budget_exceeded (402). Top up (or raise the cap), then retry — see Errors and Agents. Successful top-ups are recorded in the audit log as credits.topped_up.

The plan

Credits pay for what an agent does. The plan is separate: it is the right to use the organization at all. Every organization needs an active plan — $20 per month — before any route outside billing will answer. Without one the API returns subscription_required (402) with the message telling you exactly what to do. Creating an organization does not start a plan. Buy one, then the organization works.

Reading the plan

GET /v1/credits/subscription returns the current plan. Requires the billing:read scope, and is answerable whether or not a plan is active.
string
One of:
  • none — no plan has ever started. Every gated route is refused.
  • active — the organization can be used.
  • past_due — the last payment did not go through. The organization keeps working until grace_until, then is refused.
  • canceled — the plan ended. Every gated route is refused.
string | null
When the paid period ends, or null if no plan has ever started.
string | null
While past_due, the moment the organization stops working. null means no grace remains.
boolean
true once a cancellation has been asked for. The organization stays usable until current_period_end and is refused after it.
string | null
Always null on a read; see below.
An active plan whose current_period_end is more than three days in the past stops being honoured. Renewals reach us as signed callbacks, and a callback that never arrives must not become permanent free access. Any later callback moves the deadline forward again, so a plan that is genuinely paid heals itself the moment the next event lands.
Response

Starting or renewing the plan

POST /v1/credits/subscription opens a hosted checkout page and returns its URL as action_url. It takes no body. Requires the billing:write scope. Like a top-up, it changes nothing on its own: the organization becomes usable once the payment is confirmed, which is normally a second or two after the customer completes the page. Re-read GET /v1/credits/subscription until status is active.
Response

Cancelling the plan

DELETE /v1/credits/subscription stops the plan at the end of the period already paid for — never immediately, and nothing is refunded or charged again. Requires the billing:write scope, and like the two routes above it answers whether or not the organization is currently usable: a recurring charge you can only stop by paying first is not one a customer can stop. The organization keeps working until current_period_end, and is refused after it. Re-read GET /v1/credits/subscription to see cancel_at_period_end become true — the state follows the payment provider’s confirmation, so the read is the truth, not this response.
Response
To restart after cancelling, POST /v1/credits/subscription again.

Managing the payment method, invoices and cancellation

POST /v1/credits/billing_portal returns a link to the payment provider’s own hosted account page, where a customer can change the card on file, download past invoices, and cancel. It takes no body and requires the billing:write scope. The link is single-use and expires — follow it, do not store it. Like every other route on this page it changes nothing by itself. Whatever the customer does on that page arrives back as the same confirmed events that already move the plan, so re-read GET /v1/credits/subscription afterwards rather than assuming an outcome.
Response
An organization that has never held a plan has no account to manage, and this answers 404 not_found rather than an empty page:
404

What stays open without a plan

An organization with no plan can still identify itself, read its own billing state, and pay. Everything else is refused with subscription_required (402).
A session already running is never cut off mid-turn. The plan is checked when work is admitted — starting a session, sending it a message, or a schedule firing — not on every turn of a session already under way. A lapse stops new work; it does not kill a task in flight. Plan changes are recorded in the audit log as subscription.updated, and a customer’s own cancellation as subscription.canceled.