The node that does the work records the usage, one record per billable unit of work, and reports it to the edge within seconds. Each operation bills one unit you can see, whatever happened inside it: a scrape bills one vision.page whether the cache, a plain fetch or a browser served it.

Units

UnitProductCountsWhat it measures
vision.pagevisionpagesOne page fetched and converted, whichever tier served it (cache, fetch, browser).
vision.browser_msvisionmillisecondsWall time of a browser session, from claim to close.
render.screenshotrenderscreenshotsOne captured screenshot; extra variants of the same capture count once each.
render.video_srendersecondsSeconds of output video, rounded up per video.
infer.input_tokensinfertokensPrompt tokens.
infer.output_tokensinfertokensGenerated tokens.
infer.audio_charsinfercharactersCharacters of text synthesized to speech.
sandboxes.vcpu_mssandboxesvCPU millisecondsCPU time used, sampled from the sandbox cgroup cpu.stat.
sandboxes.gib_mssandboxesGiB millisecondsAllocated memory times wall time while running.
routines.effect_steproutinesstepsA routine step with effects that has no product meter of its own (core/http, core/wait, …).
actions.callactionscallsOne action execution.
egress.bytesplatformbytesBytes of customer-steered egress, recorded by the egress guard for every operation.

A few rules follow from "one unit per operation":

  • vision.browser_ms applies to browser sessions only. Scrapes that used a browser bill vision.page and nothing else.
  • A routine step bills its product's unit: a vision/scrape@1 step bills vision.page. Only steps with no product meter of their own, such as core/http@1, bill routines.effect_step.
  • A paused sandbox bills no CPU time. Whether it bills memory while paused is still being settled for the beta; the sandbox's usage shows what it was charged.
  • A map bills one vision.page per request, however many URLs it returns. An extraction bills its pages plus the model's tokens.
  • Work done before a cancel stays billed: scraped pages, encoded video seconds, tokens already generated.

Inference is free in the beta, within each model's token-per-minute limit. Your organization's credit balance is in the dashboard.

Totals

GET /v1/usage adds up usage between start and end (default: this calendar month so far), grouped by any of product, unit, key, project and day:

bash
curl -s "https://beta-api.b3os.org/v1/usage?group_by=product,unit" \ -H "Authorization: Bearer $B3OS_API_KEY"
json
{ "object": "usage_summary", "start": "2026-10-01T00:00:00.000Z", "end": "2026-10-25T22:00:00.000Z", "group_by": ["product", "unit"], "rows": [ { "product": "vision", "unit": "vision.page", "qty": 18204 }, { "product": "sandboxes", "unit": "sandboxes.vcpu_ms", "qty": 9120330 }, { "product": "infer", "unit": "infer.output_tokens", "qty": 4410920 } ]}

The values are illustrative. The last minute of usage may still change as nodes report.

Records

GET /v1/usage/records lists the individual records, newest first, and filters by product, unit, key and request. Every record names the request that produced it, so you can tie a charge to a call:

json
{ "id": "use_01m5t5tmscqev5tf32q87tr1v5", "object": "usage_record", "ts": "2026-10-25T21:30:00.120Z", "key_id": "key_01m5t5csy2wt4e3er052chyf1x", "sandbox_id": null, "node": "n1", "product": "vision", "unit": "vision.page", "qty": 1, "request_id": "req_01m5t4yg394wegr3j4y01qb363", "meta": { "tier": "fetch" }}

This example is abridged. Calls made from inside a sandbox carry its sandbox_id, and they bill the key that created the sandbox.

Caps

A key can carry a spend cap in USD (spend_cap_usd). When the key reaches it, its requests fail with spend_cap_exceeded until you raise the cap. A sandbox's api.spend_cap_usd caps the calls made from inside that sandbox. When the organization runs out of credits, requests fail with credits_exhausted. The node enforces caps with its own counters, so calls that never pass through the edge are capped too.

Ask a question... ⌘I