Usage and metering
What B3OS meters, which unit each operation bills, and how to read your usage as totals or as the individual records behind them.
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
| Unit | Product | Counts | What it measures |
|---|---|---|---|
vision.page | vision | pages | One page fetched and converted, whichever tier served it (cache, fetch, browser). |
vision.browser_ms | vision | milliseconds | Wall time of a browser session, from claim to close. |
render.screenshot | render | screenshots | One captured screenshot; extra variants of the same capture count once each. |
render.video_s | render | seconds | Seconds of output video, rounded up per video. |
infer.input_tokens | infer | tokens | Prompt tokens. |
infer.output_tokens | infer | tokens | Generated tokens. |
infer.audio_chars | infer | characters | Characters of text synthesized to speech. |
sandboxes.vcpu_ms | sandboxes | vCPU milliseconds | CPU time used, sampled from the sandbox cgroup cpu.stat. |
sandboxes.gib_ms | sandboxes | GiB milliseconds | Allocated memory times wall time while running. |
routines.effect_step | routines | steps | A routine step with effects that has no product meter of its own (core/http, core/wait, …). |
actions.call | actions | calls | One action execution. |
egress.bytes | platform | bytes | Bytes of customer-steered egress, recorded by the egress guard for every operation. |
A few rules follow from "one unit per operation":
vision.browser_msapplies to browser sessions only. Scrapes that used a browser billvision.pageand nothing else.- A routine step bills its product's unit: a
vision/scrape@1step billsvision.page. Only steps with no product meter of their own, such ascore/http@1, billroutines.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
usageshows what it was charged. - A map bills one
vision.pageper 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:
bashcurl -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.