Billing

Reading your own balance and usage — and one honest limit on where from.

Every amount is an integer

Every amount on this platform — balance, usage cost, a top-up, a line on a statement — is an integer number of the currency's smallest unit, never a float. 1999 with currency: "USD" is $19.99. The exponent is not assumed: it travels with the amount as minor_exponent (2 for USD/EUR/GBP/AED, 0 for IRR/IRT/TOMAN, which have no subunit in practice), so 500 with minor_exponent: 0 is 500 units whole, not 5.00. Divide by 10 ** minor_exponent yourself; never trust a pre-formatted string for a calculation.
The shape of every amount
{"amount_minor": 1999, "currency": "USD", "minor_exponent": 2, "display": "19.99"}

Where these endpoints live

This is the console's API, not `/v1`
Said plainly, because a developer reaching for a Bearer token here will get a confusing failure otherwise: these endpoints authenticate with the signed-in browser session that runs the console, the same origin, under /api/accounts/billing/* — not with an API key, and not under /v1. There is currently no way to read balance or usage with an sk-larsa-… key. If you need this automated outside a browser, the working approach today is to drive the console session (submit the sign-in form, keep the cookie jar) rather than expecting your API key to open the door.

The endpoints

GET/api/accounts/billing/balance
Response
{
  "org_id": "org_9k2m...",
  "currency": "USD",
  "balance": {"amount_minor": 4231, "currency": "USD", "minor_exponent": 2, "display": "42.31"},
  "month_usage": {"amount_minor": 1269, "currency": "USD", "minor_exponent": 2, "display": "12.69"},
  "monthly_cap": null,
  "tier": "paid",
  "blocked": false,
  "blocked_reason": ""
}
GET/api/accounts/billing/transactions
ParameterTypeDescription
limit
Optional
integer1 to 200.
Default: 50
before_id
Optional
integerKeyset pagination, not an offset — see Pagination below.
Response
{
  "object": "list",
  "org_id": "org_9k2m...",
  "data": [
    {"id": 4821, "kind": "usage", "amount_minor": -37, "currency": "USD",
     "balance_after_minor": 4231, "ref": "req_a1b2", "description": "larsa-general",
     "created_at": "2026-08-26T09:14:02Z", "created_by": null}
  ],
  "next_before_id": 4820
}
GET/api/accounts/billing/usage
ParameterTypeDescription
days
Optional
integer1 to 366. Both the per-model totals and the daily series cover this same window, so they always agree with each other.
Default: 30
Response
{
  "org_id": "org_9k2m...", "window_days": 30, "currency": "USD",
  "total": {"amount_minor": 1269, "currency": "USD", "minor_exponent": 2, "display": "12.69"},
  "data": [
    {"model": "larsa-general", "prompt_tokens": 402113, "completion_tokens": 88221,
     "requests": 512, "cost": {"amount_minor": 890, "currency": "USD", "minor_exponent": 2, "display": "8.90"}}
  ],
  "daily": [
    {"day": "2026-08-25", "requests": 41, "tokens": 19332,
     "cost": {"amount_minor": 61, "currency": "USD", "minor_exponent": 2, "display": "0.61"}}
  ]
}
GET/api/accounts/billing/statements

Every calendar month this org has a statement for, newest first — a month that only saw a top-up and no API calls still appears, because a customer looking for it should find it, not a 404.

GET/api/accounts/billing/statements/{period}
ParameterTypeDescription
period
Required
stringYYYY-MM, e.g. 2026-08.

Nothing is stored when a statement is rendered — it is usage_event (what was consumed) plus ledger (what was paid) grouped by month, at read time. Re-rendering last March in two years produces the same document, and a correction posted today shows up in the month it was posted, never rewriting a document already issued.

Pagination

/billing/transactions uses keyset pagination on the ledger's own id, not OFFSET. The ledger only ever grows at the head, so an offset would shift every page under a reader the moment a new usage row lands mid-scroll — rows would repeat or vanish. Pass the previous page's next_before_id as before_id to fetch the next one; a null means you have reached the end.

Calling it with a session

Every sample below sends the console's session cookie rather than a Bearer token — sign in through the console's own form first and keep the cookie jar your HTTP client already gives you.

# sign in once, keep the cookies, then read balance from the same origin
curl -c cookies.txt -s https://api.console.larsa.larsima.com/api/accounts/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "…"}' > /dev/null

curl -b cookies.txt https://api.console.larsa.larsima.com/api/accounts/billing/balance
Navigate Open esc Close