Practice wallet

"mode": "paper" · ATLAS · GET /flow/v1/auth/account/paper · POST …/paper/deposit
Live

Every account has a play-money wallet in ATLAS, with free top-ups, running the same order path as real money: real venue prices, real settlement, one code path. Ship the whole product before anyone deposits a dollar.

What you skip

OpenMarkets handles

  • A ledger per account, and the balance on it
  • Fills at the best live price on a real venue, on the internal OpenMarkets book
  • Settlement and grading through the same resolution path as a real order
  • Per-model and per-currency performance that never blends ATLAS with USD

You do

  • Send "mode": "paper" on a leg
  • Show the ATLAS balance next to, never added to, real money
  • Top up when a user runs dry

Paper is a mode, not an environment

Any execution credential can place a paper order — a live key, a test key, an app's install key, a person's session — by putting "mode": "paper" on the leg. The order books against the OpenMarkets practice venue at the venue quote you named, and settles when the market does.

POST /flow/v1/auth/orders/buy
{
  "model_id": "m_…",                       // optional — file it under a model
  "orders": [
    { "liquidity_hash": "kalshi:ct_abc123:…", "amount": 25, "max_price": 0.62, "mode": "paper" }
  ]
}
  • On a live key, mode defaults to real; paper must be asked for.
  • On a test key, a leg without mode is rejected rather than assumed — see Test mode.
  • A position is paper-bettable when it has a registered resolver and a real quote behind it; the liquidity feed says so per position with paper_bettable.
  • Placing needs trade:execute (Pro and up, or an app that holds it for the user); reading the wallet needs account:read.
Never add ATLAS to USD. They are different currencies in separate buckets. Balances, positions and performance are all partitioned by currency for exactly this reason — render each on its own.
GET/flow/v1/auth/account/paper

The practice wallet: the ATLAS balance, the largest single top-up, and the cap the balance may not exceed. Acts on the key's own account, or on a Connect user with X-OpenMarkets-Account.

Try it
GET/flow/v1/auth/account/paper
Response.data
{
  "currency": "ATLAS",
  "balance": 1000,
  "max_deposit": 100000,
  "balance_cap": 10000000
}
POST/flow/v1/auth/account/paper/deposit

Top the wallet up. Body { amount, description? } — amount above 0, at most two decimals, at most max_deposit (400 invalid_amount), and the result may not exceed balance_cap (409 balance_cap). Needs trade:execute, the same gate as placing a paper order. Send an Idempotency-Key; the reply is 201 with the new balance and the ledger entry.

Request + Response
// Request body
{ "amount": 500, "description": "weekly top-up" }

// 201 · Response.data
{ "currency": "ATLAS", "amount": 500, "balance": 1500, "om_ledger_id": "led_…" }
GET/flow/v1/auth/account/paper/ledger

The wallet's ledger, newest first. type is one of opening_balance, bet_debit, settlement_credit, refund, adjustment, deposit. Each entry names the order that moved it, when one did.

NameInTypeRequiredDescription
limitqueryintegernoMax 200
Try it
GET/flow/v1/auth/account/paper/ledger?limit=50

Max 200

Response.data
{
  "currency": "ATLAS",
  "entries": [
    { "ledger_id": "led_…", "type": "settlement_credit", "amount": 40.32, "balance_after": 1515.32,
      "router_order_id": "ro_…", "description": null, "created_at": "2026-09-22T04:10:00Z" },
    { "ledger_id": "led_…", "type": "bet_debit", "amount": -25, "balance_after": 1475,
      "router_order_id": "ro_…", "description": null, "created_at": "2026-09-22T03:02:11Z" },
    { "ledger_id": "led_…", "type": "deposit", "amount": 500, "balance_after": 1500,
      "router_order_id": null, "description": "weekly top-up", "created_at": "2026-09-21T18:00:00Z" }
  ]
}

Where else it shows up

  • GET /auth/account/balances returns an ATLAS bucket beside the USD one — see Venues & balances.
  • GET /auth/performance and every model read partition by currency, so a paper strategy and a real one never share a number — see Models & attribution.
  • A Connect flow can be marked practice-only, so an organization's users trade in ATLAS without linking a real venue at all.

Coming next

OM-08 · Wallet SDK · Soon

Real-money balances, paid features and payouts, on the same wallet model. Planned, not available; nothing here promises a date. The practice wallet is the live rung.

Next