Billing & budgets
Two per-minute meters, a quote before every job, and hard stops at both the run and the account level.
Everything you buy here reduces to two meters: robot-hours (occupancy of an embodiment) and environment-hours (occupancy of a scene), metered per minute. A queue priority multiplies both — burst ×1.5, standard ×1.0, soak ×0.6. Both meters appear in every quote and every result, so a bill is always reconstructible from numbers you already saw. The full rate card is on the pricing page.
Quote first
A quote resolves both meters, the dollars, and the queue before you commit
anything. The worked example: 600 episodes of g1-edu-pro in
kitchen-std@v1.2 at standard priority estimates 2.0 minutes per episode, so
20.0 robot-hours × $148 plus 20.0 environment-hours × $39 — $3,740, queue ETA
about 6 hours. Quotes expire after seven days; a stale one is refused with
quote_expired.
import roborama # reads ROBORAMA_API_KEY from the environment
quote = roborama.quote(
robot="g1-edu-pro",
environment="kitchen-std",
episodes=600,
)
print(quote)
# {robot_hours: 20.0, env_hours: 20.0, usd: 3740, queue_eta: "6h"}The run-level hard stop
Every run accepts max_budget_usd, metered live against both meters. A run
that hits the cap stops with budget_exceeded and keeps the partial result —
n, success rate, and ci95 for the episodes that did run. A run stopped at
episode 81 still tells you things; it just tells you them with a wider
interval. Codes and envelope shapes are catalogued at
the error reference.
Account-level controls
import roborama # reads ROBORAMA_API_KEY from the environment
usage = roborama.usage(period="2026-09")
print(usage) # robot_hours by tier, env_hours by class, $
roborama.budgets.set(monthly_usd=25_000, hard=True) # hard stop, metered
key = roborama.keys.create(scope=["runs:write", "streams:read"])
print(key.id) # secret shown once, rbr_live_ prefix
receipt = roborama.data.purge("run_8842") # customer-initiated deletion
print(receipt.id, receipt.status) # receiptedFour controls, one per line of that example:
roborama.usage(period="2026-09")— robot-hours by tier, environment-hours by class, and dollars, mid-month. These are the same numbers the invoice will use.roborama.budgets.set(monthly_usd=25_000, hard=True)— an account-wide hard stop. Once spend crosses the cap, new runs are refused withmonthly_budget_exceededuntil the period rolls over.roborama.keys.create(scope=["runs:write", "streams:read"])— scoped keys, least privilege. A CI key needsruns:writeand nothing else; a triage dashboard needsstreams:read; keepdata:purgeon a human-held key. A call outside a key's scope fails withinsufficient_scope, which is the point.roborama.data.purge(run_id)— customer-initiated deletion. The response is a receipt with an id and status, so the deletion is a fact you can file, not a support ticket you can hope about.
Spending less on purpose
The tiers are the tool. Iterate on the soak tier — nori-a3 pods at
$7/robot-hour, or soak priority at ×0.6 on any embodiment — and reserve
verification-tier hardware for the runs that produce reports someone will
cite. If managing that ladder sounds like a job for a machine,
threshold() is that machine: it iterates on
soak, escalates to the verification tier only when the target is crossed, and
takes a monthly_cap_usd of its own.