Zero to a validated first bill
A workspace, a plan, a customer, a subscription, one usage event — and a rated invoice you can read line by line. Everything below runs in the test environment — no processor, no card, no money moves. The full endpoint reference is at /docs.
01
Create your workspace
Create your account and name your organization. That one step provisions everything: a merchant account plus separate test and live environments, fully isolated from each other. You land in test mode, where the rest of this page happens.
02
Follow the Launch guide
A new workspace lands on the Launch guide — a checklist whose progress is derived from your actual billing data, not ticked boxes. It walks you through billing identity, your first plan (guided setup, plus one-click starters for AI/token, seat, and usage pricing that create the customer along the way), a test customer, and a subscription. Prefer to do those over the API instead? Step 4 below is the same chain in curl.
03
Mint a test API key
In the cockpit: Settings → API keys. Keys look like roi_sk_test_…, are shown once, and roi stores only a keyed hash. A test key can only ever reach test data — there is no header or flag that lets it touch live.
export ROI_API_KEY=roi_sk_test_...
04
Create a customer and subscription
Objects take your identifiers via external_id, so your product never stores roi UUIDs. Creating the same external_id twice returns a conflict rather than a duplicate — safe to retry.
Unrecognised fields are rejected rather than ignored, so a typo fails on the first call with the field named in param. Every error type is listed at /docs/errors.
curl https://api.billroi.com/v1/customers \
-H "Authorization: Bearer $ROI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"external_id":"workspace_42","name":"Acme AI","email":"billing@acme.test"}'A subscription needs a plan. Grab the id from the plan you created in the Launch guide — it is on the pricing page, or one GET /v1/plans away.
curl https://api.billroi.com/v1/subscriptions \
-H "Authorization: Bearer $ROI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_id": "workspace_42_pro",
"customer_external_id": "workspace_42",
"plan_id": "PLAN_ID"
}'This starts a durable billing workflow: period close, rating, invoicing, and — once money is involved — retries all run inside it. No payment method is required in test; without one, invoices simply collect as invoices rather than auto-charges.
05
Send a usage event
Metered billing is one POST per product fact. The idempotency_key is yours — use your business event id, and retries become safe.
curl https://api.billroi.com/v1/usage \
-H "Authorization: Bearer $ROI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subscription_external_id": "workspace_42_pro",
"event_name": "generation.completed",
"properties": {"tokens": 1200, "model": "gpt-4.1", "token_type": "input"},
"quantity": 1,
"source": "quickstart",
"idempotency_key": "event-0001"
}'The cockpit's API-keys page renders this exact snippet with your real key and subscription pre-filled, plus Node and Python variants — and an MCP config, if you want an AI agent reading your billing data.
06
Validate your first bill
Back in the Launch guide, Validate first bill runs the entire invoice waterfall — rated subtotal, minimum true-up, tax, amount due, per-line margin — as a read-only pass. No invoice, payment, credit, or ledger state is created. This is the proof that your pricing does what you think it does, before a processor is anywhere near it.
07
See a year of billing, without waiting a year
The part of a billing integration you cannot check by reading it is what happens on the second invoice, and the twelfth. A test clock is a virtual now: pin a subscription to one and its periods close when you move the clock, not when a month passes.
curl https://api.billroi.com/v1/test-clocks \
-H "Authorization: Bearer $ROI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"frozen_at":"2026-01-31T00:00:00Z"}'Create the subscription with test_clock_id, send it some usage, then move the clock a year:
curl https://api.billroi.com/v1/test-clocks/CLOCK_ID/advance \
-H "Authorization: Bearer $ROI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"by":"1y"}'
{ "frozen_at": "2027-01-31T00:00:00Z",
"invoices_created": 12,
"amount_billed_minor": 36300,
"settled": true }Two seconds, twelve real invoices, each rated over its own month by the same workflow that bills production. The call does not return until every one of them exists, so there is nothing to poll and no sleep to put in your test suite. Usage you send is stamped with the clock's time, and stepping a month at a time from the 31st follows the anniversary the way billing does: Feb 28, Mar 31, Apr 30. Test environment only.
One limit worth knowing before you rely on it: a clock moves billing periods, not the dunning workflow's retry timers. A clock-bound subscription whose card declines still waits the real interval between attempts, so advancing a year exercises twelve closes, not twelve recovery ladders.
08
Go live when you are ready
Connect the processor you already have — Stripe connects over OAuth; others take their API credentials on the Connections page — then promote your certified test configuration to live from the Launch guide. roi only ever holds processor-minted references, never card data: your PSP keeps the vault, the merchant agreement, and the funds flow.
Live opens with its own checklist because customers, cards, subscriptions, keys and processor secrets are intentionally never copied from Test. For Stripe, add a payment method from the customer page — card entry stays on Stripe Checkout — then review and explicitly approve the first live invoice. Launch is complete only after its collection reaches paid.