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. A company being set up cannot top up: it runs on its one-time setup credit, and its next step is the plan. The call is refused with subscription_required (402) until the company is activated.
integer
required
Amount to add, in micro-USD.
string
Optional app-relative path to preserve through the hosted checkout. Absolute and protocol-relative URLs are refused.

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 before any route outside billing will answer. Without one the API returns subscription_required (402) with the message telling you exactly what to do. Included credit is added to the prepaid balance and rolls over: it never expires. 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.
A free trial reads active too: there is no trialing status. trial_end says the trial is running.
string | null
standard or pro. null until the organization first subscribes.
integer | null
The plan’s monthly list price — 20000000 or 200000000. null while plan is.
integer | null
The credit each paid month adds to the balance. null while plan is.
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
While the free trial is running, the moment it converts to a paid Standard month. null otherwise.
string | null
The plan a scheduled downgrade moves to at current_period_end, else null.
boolean
Whether POST with {"plan": "standard"} from this caller would start the free trial. One trial per organization and one per person: an organization that already had a plan is not offered one, and neither is an organization whose caller, owners or creator — under any +tag or Gmail-dot spelling of their address — asked for a trial at another organization that started one (or one opened there in the last 24 hours), or belongs to or created an organization that used one. Leaving an organization does not reset it.
integer
The free trial’s length on this deployment, in days. 0 when trials are off.
integer
The credit the free trial starts with. 0 when trials are off.
string[]
The plans this deployment sells: ["standard", "pro"], or ["standard"] where Pro is not offered. POST or PATCH with a plan not listed answers 501 feature_not_configured.
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 (201). The body is optional: {"plan": "standard"} (the default — an empty body is Standard) or {"plan": "pro"}. Requires the billing:write scope.
string
default:"standard"
standard or pro.
The free trial. When the plan is standard and trial_eligible is true, the checkout starts a 7-day free trial: a card is required on the page, $10 of credit is granted when the trial starts (on an eligible card: see [Pricing](/platform/pricing)), and unless it is cancelled first the trial converts to $20 per month — with the full $20 of credit — when it ends. Cancel during the trial (DELETE below, or the account page) and nothing is charged. A caller who is not eligible gets the same checkout without the trial, billed on the day. Pro has no trial. Like a top-up, it changes nothing on its own: the organization becomes usable once the payment (or the trial) 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. An organization whose plan is already active is refused with state_conflict (409): a second checkout would be a second plan billed. Change the tier with PATCH below instead. A company being set up starts here: the payment that makes its plan active activates it (setting_up turns false), and the crew it held while it was set up is built (installs).
Response

Changing the plan

PATCH /v1/credits/subscription with {"plan": "pro"} or {"plan": "standard"} changes an active plan in place. Requires the billing:write scope; audited as subscription.plan_changed.
string
required
standard or pro.
  • Standard → Pro is immediate. The difference for the rest of the current month is charged at once on the card already on file, the billing date stays the same, and the answer reads plan: "pro". Upgrading during the free trial ends the trial and charges $200 now. The proration invoice grants what it collected as credit, up to $200.
  • Pro → Standard takes effect at the end of the period already paid for. Nothing is refunded and the Pro credit already granted is kept. Until then the plan reads plan: "pro" with pending_plan: "standard"; asking for pro again before then takes the downgrade back, free.
  • Asking for the plan already held, with nothing pending, changes nothing and answers 200.
  • An organization with no active plan is refused with state_conflict (409) naming POST.
  • A plan set to cancel at the end of its period is refused with state_conflict (409): there is no plan to change.
Like every route here, the read is the truth: the answer reports what was asked, and the confirmed callback rewrites it a moment later.
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
Cancelling also drops a scheduled downgrade. Cancelling during the free trial ends it at trial_end with nothing charged. To restart after cancelling, POST /v1/credits/subscription again — without a second free trial.

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 company being set up (organizations) has no plan yet but is not locked: on top of the column above, it may run its CEO chat — reading and making its CEO, the CEO’s sessions and their messages, events and plans, recording a template as held, renaming the company and setting its logo and brand kit — on the setup model, paid for by its setup credit. Files, transcription, voice and everything else in the right-hand column stay subscription_required (402) until it is activated.
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.