*_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.
?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 viaaction_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 inpending or requires_action, so the status on the create response is not always the final word.
Two ways to reach the terminal state:
- Poll the balance.
GET /v1/credits/balancereflects 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/ledgerlists entries newest-first; the settled top-up appears as acreditentry. Match it bycreated_atandamount_micro_usd.
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 returnssubscription_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 untilgrace_until, then is refused.canceled— the plan ended. Every gated route is refused.
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.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"withpending_plan: "standard"; asking forproagain 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
activeplan is refused withstate_conflict(409) namingPOST. - A plan set to cancel at the end of its period is refused with
state_conflict(409): there is no plan to change.
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
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
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 withsubscription_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.