Test and live
Every brand runs in two modes at one address, and the key picks the mode, with the same simulation on your machine before either. Test mode simulates AI, money, outside systems and members, takes magic values that pick each branch, and runs on test clocks, so a whole season runs before a buyer sees it. Every key runs in test on every plan.
Test mode answers one question: does every branch of the Service work before anything real happens? A brand serves both modes at the same address. An sk_test_ key reaches test mode and an sk_live_ key reaches live, and no job, member, subject or dollar ever crosses between them.
| On your machine | Test mode | Live | |
|---|---|---|---|
| Version | your folder as it stands, reloaded on save | the newest tested version | the version deploy --live promoted |
| Served by | services.dev dev, at localhost:8787 | your brand's address, to sk_test_ keys | your brand's address, to sk_live_ keys |
| AI | simulated | simulated, unless you set --model live on a test key | your model key, at cost |
| Money | recorded, never moved, and no Stripe | recorded on the ledger, never moved | charged, released, refunded and paid out on your Stripe account |
| Outside systems | the sandbox, steered by magic values | the same sandbox | the real endpoint and its receipt |
| Members | the simulated market | the simulated market, and your staff | the people in your Pool |
| Time | your clock, or a test clock | the brand's clock, or a test clock you advance | the brand's clock |
| Every answer | carries simulated: true | carries simulated: true | carries simulated: false |
| Plan | every key, on every plan | every key, on every plan | each key on the plan that carries it |
| Deploy | Serves at | Plan |
|---|---|---|
| test and live | <brand>.builder.domains | every plan |
| your own domain | Brand.domain, with its certificate renewed for you | Launch |
| a preview of a branch | services.dev preview, on test keys, at its own address | Team |
| private, in your region | services.dev deploy --region eu, data kept there | Scale |
A magic value makes a job take one branch with no person and no outside system: a party who never answers, a filing rejected once, a member whose coverage lapsed. Set it on the order's metadata.sandbox, as a party's email, or on a test clock for every job it holds. The reference lists all of them and the pages that show each one.
apis.tax runs its whole spring before February. A test clock carries its own market, here 40 simulated preparers who ask more than reviews post at:
npx services.dev test-clocks create 2027-01-15 --members 40 --market tight← tc_9Ts1 · test clock · frozen at 2027-01-15T14:00:00Z · market tight, 40 simulated members in preparers · test mode onlynpx services.dev subscriptions seed tax-plan --count 120 --test-clock tc_9Ts1← 120 Tax Plans on tc_9Ts1 · 120 simulated taxpayers · entities and states drawn from the seed 9Ts1 · simulated: trueThen three months, in one call. Every rung, mint, rejection, raise and extension fires in order, the same way it would on the brand's clock. The test clock's rules and the timers it fires are on Timers and replay:
npx services.dev tick 2027-04-16 --test-clock tc_9Ts1apis.tax · test mode · tc_9Ts1 · 2027-01-15 → 2027-04-16 · version 2027-01 · market tight
minted 120 annual returns on 1 Feb, one for each Tax Plan
filed 104 federal and 212 state returns · 9 rejected once, each repaired inside its window
extended 16 returns, by each file clock's run tentative 3d rung · 0 dates missed
fill 113 reviews · p90 3h40m to claim · raised 38 times · widened 4 · 0 unreached
money recorded, never moved · 120 Tax Plan cycles, $288,000.00 · each return $0, inside its plan · signers' pay $9,420.00, preparers' $1,215.00
every act simulated: true · nothing reached the IRS, a state, Stripe or a memberThe brand's own suite runs on the same clock, as deploy runs it:
npx services.dev verify --test-clock tc_9Ts1apis.tax · 258 cases from 84 rows · test mode · 2027-01 on tc_9Ts1
258 passed · 0 failed · 72 live rows wait for deploy --liveThe owner console shows test mode with the same screens, behind a test banner, so what you check in test is what you will read live.
| Call (CLI) | API | Event | On the console | Plan |
|---|---|---|---|---|
test-clocks create <time> [--members N --market tight] | POST /test_clocks | test_clock.created | /console | every plan |
subscriptions seed <service> --count N --test-clock <tc> | POST /test_clocks/:id/seed | subscription.created | /console | every plan |
verify --test-clock <tc> | GET /verify/suite.json | none: it reads | /console/deploys | every plan |
dev [--port 8787] | none: it serves your folder on localhost | none: it reads | — | every plan |
preview | POST https://services.dev/v1/previews | version.tested | /console/deploys | Team |
deploy --region <region> | POST https://services.dev/v1/deploys { region } | version.deployed | /console/deploys | Scale |