Sandbox vs production
Which keys reach real money.
The key prefix decides the environment and nothing else does — wr_test_ is sandbox, wr_live_ is production.
wr_test_... sandbox
wr_live_... productionSandbox is the default
Every organisation starts in sandbox, and it is where everything in these docs runs. Balances are seeded, no real money exists, and the whole lifecycle behaves identically — the same state machine, the same policy engine, the same clause evaluation.
Production requires an explicit unlock. It is not a flag you can flip by accident on the way to shipping.
A key cannot reach the wrong environment
A wr_live_ key presented against a sandbox organisation resolves to no
principal at all. That is a 401, not a 403: there is nobody to refuse.
It is the same answer a made-up key gets, and the same body, so probing tells you nothing about which half was wrong.
What differs, and what does not
| Sandbox | Production | |
|---|---|---|
| Key prefix | wr_test_ | wr_live_ |
| Money | Seeded, not real | Real |
| State machine | Identical | Identical |
| Policy engine | Identical | Identical |
| Clause evaluation | Identical | Identical |
| Rate limits | Same | Same |
The engine being identical is the point of having a sandbox at all. A spec that
passes there passes here, and POST /bench/run lets you check one without a key
or a warrant.
Running the API locally
With no DATABASE_URL set and WARRANT_ENV on its sandbox default, the API
boots an in-process PGlite database and seeds it. Data is real but ephemeral and
is rebuilt on every restart.
pnpm --filter @warrant/api devSign in at the console as owner@sandbox, admin@sandbox, operator@sandbox
or viewer@sandbox to see each role's view.
That fallback is refused on a serverless deployment, where each cold start would get its own empty database — a failure that would look like data loss rather than like misconfiguration.
The chain flag is separate
WARRANT_CHAIN decides whether traces anchor to Rialo testnet. It defaults to
mock, which keeps tests offline and deterministic.
WARRANT_CHAIN=mock # MockRex + PostgresLedger (default)
WARRANT_CHAIN=rialo # RialoRex + RialoLedger, live testnetUnder rialo, custody still delegates to the Postgres ledger. Anchoring is
real; onchain settlement is not — see contracts.
Amounts do not change between environments
"8400000" 8.40 USDC
8400000 rejected — a JSON number
"8.40" rejected — not the smallest unitInteger strings of the smallest unit, ^[0-9]+$, in both.