Skip to main content
Six methods. Every monetary value is integer micro-USD — the client never exposes a float and never converts to dollars; formatting is your presentation decision. API detail: Credits.

show

GET /v1/credits/balance:
79416537 micro-USD is $79.416537.

topup

POST /v1/credits/topups, body { amount_micro_usd }. Opens a hosted checkout and credits nothing — only the verified provider callback moves the balance. Send the person to the returned URL.

ledger

GET /v1/credits/ledger. LedgerFilter extends the page query with type ("debit" | "credit"), session_id, agent_id, deployment_id, from, and to — every movement, attributable to what spent it.

spend

GET /v1/credits/spend. What the matching debits spent, summed by the server over the whole range: spent_micro_usd, by_tier, and the 50 dearest by_agent and by_session. days (alone, 1 to 90) adds by_day, the company’s spend per day on timezone’s clock. Use it for any total or chart: a sum over one ledger page misses every debit past it.

subscription

GET /v1/credits/subscription — the plan, which is the right to use the organization at all:
status is none | active | past_due | canceled. Every route outside billing answers 402 subscription_required until it reads active. While past_due, grace_until is the moment the organization stops working. action_url is null on a read. plan is "standard" | "pro" | null (null before the first subscription), with its monthly price_micro_usd and included_credit_micro_usd. A free trial reads status: "active" — there is no trial status — with trial_end set while it runs. pending_plan is a downgrade scheduled for current_period_end. trial_eligible says whether subscribe({ plan: "standard" }) would start the 7-day free trial. trial_days and trial_credit_micro_usd are the trial’s length and starting credit on this deployment (0 when trials are off). plans lists each plan this deployment sells as { plan, price_micro_usd, included_credit_micro_usd }, readable before subscribing. The plan fields are optional in the schema, so the client still parses an older server that omits them. includePaymentMethod: true adds payment_method, the card the plan bills ({ last4 }, or null when there is none or it could not be read), read from the payment provider at call time. It needs a key with billing:write; without it the call is refused with 403 forbidden.

subscribe

POST /v1/credits/subscription. Opens the hosted checkout for the plan — Standard by default, with the 7-day free trial when trial_eligible — and answers action_url. Send the person there; nothing changes until the signed callback lands. An organization whose plan is already active throws ApiError state_conflict: use changePlan.

changePlan

PATCH /v1/credits/subscription. Changes an active plan. "pro" is immediate: the difference for the rest of the month is charged now on the card on file, and a running trial ends with $200 charged. "standard" from Pro takes effect at current_period_end — nothing refunded, the Pro credit kept — and reads back as pending_plan: "standard"; changePlan("pro") before then takes it back. The plan already held with nothing pending is a no-op. No active plan throws state_conflict.

cancelSubscription

DELETE /v1/credits/subscription. Stops the plan at the end of the period already paid for — never immediately. The state follows the provider’s callback, so the answer reports the request, not a completed change (cancel_at_period_end: true).

billingPortal

POST /v1/credits/billing_portal. Returns a link to the payment provider’s own hosted account page — change the card, download invoices, cancel. Send the person to action_url; it is single-use and expires, so mint one per visit rather than caching it.
An organization that has never held a plan has no account to manage: the call throws ApiError with code not_found. Catch it and offer subscribe() instead.