Skip to content

API reference

Account

Read your sandbox account, open positions, and closed-trade history.

Everything you need to know your agent's current state on the sandbox: the account, its open positions, and its trade history. Your real accounts are read through the live routes instead; see Live trading.

Read your account

GET/sandbox/accountAPI key

Your sandbox account: balance, equity, unrealized PnL, the challenge floors and target, phase, and lock status. The idle liquidation monitor and the auto-pass run on read, so an underwater account reflects its true state and an account at its target has already been passed.

{  "account": {    "id": "demo",    "environment": "sandbox",    "balance": 50000,    "equity": 50120.50,    "unrealizedPnL": 120.50,    "startingBalance": 50000,    "challengeSize": 50000,    "profitTarget": 55000,    "dailyLossFloor": 48000,    "globalLossFloor": 47000,    "evalType": "1-step",    "phase": 1,    "profitSplit": 0.8,    "status": "ACTIVE",    "isLocked": false  }}

Two of these fields decide whether your agent thinks it has passed and what it thinks it earns, and both are easy to read in the wrong unit. The whole table, with units stated:

FieldUnitNotes
balancedollarsRealized only. Closed PnL and fees are in it; open positions are not.
equitydollarsbalance plus unrealized PnL. This is the number the floors are tested against.
unrealizedPnLdollarsequity - balance.
startingBalancedollarsWhat the account opened at.
challengeSizedollarsThe nominal account size.
profitTargetdollars: an absolute balance level, not a deltaA $50K 1-step at +10% publishes 55000, not 5000. The account passes when balance >= profitTarget with no open positions; testing against a delta passes on tick one.
dailyLossFloordollars: an absolute equity levelBreached when equity falls to or below it. Trails the daily high-water mark.
globalLossFloordollars: an absolute equity levelStatic for the life of the account.
profitSplitfraction, not percent0.8 means 80%. Multiplying by a further 100 overstates any payout estimate by 100×.
evalTypestringAlways 1-step on the sandbox. A live account can be any of: 1-step, gauntlet, hyper, 2-step.
phaseinteger1-based. A 2-step account advances to 2 on passing phase 1.
statusstringACTIVE, PASSED, or FAILED.
isLockedbooleantrue after a breach. Every write returns 403 account_locked until you reset.

The floors are levels, not distances

All three of profitTarget, dailyLossFloor and globalLossFloor are absolute levels in dollars. None of them is a distance from your balance, and none is a percentage. The comparisons your agent needs are equity <= dailyLossFloor (or globalLossFloor) to breach, and, for the pass, equity - closeFees >= profitTarget, where closeFees is the taker fee (0.045%) on size × markPrice for every open position.

The pass is automatic

The pass is decided on realized balance with no position open, and your agent does not have to do the closing. On the read that sees your equity, after the taker fees to close every open position, at or above profitTarget, the sandbox closes all of your positions at that read's marks and passes the account on the balance that close produces (on a 2-Step phase 1, phase 2 starts). The fees are counted first, so the close lands at or above the target. Those closes appear in your trade history as market. A position with no mark on that read holds the whole close back until the next read. The live engine applies the same rule on every tick, without waiting for a read.

List open positions

GET/sandbox/positionsAPI key

Your open positions with unrealized PnL. markPrice and unrealizedPnL are null when the feed did not price a symbol on this read.

{  "positions": [    {      "symbol": "BTC", "side": "long", "size": 0.1, "leverage": 5,      "entryPrice": 64000, "markPrice": 64250, "notionalValue": 6400,      "marginRequired": 1280, "unrealizedPnL": 25,      "takeProfitPrice": null, "stopLossPrice": null,      "openedAt": "2026-07-01T12:00:00.000Z"    }  ]}

Trade history

GET/sandbox/tradesAPI key

Your closed-trade history (realized PnL and fee), newest first.

{  "trades": [    {      "id": "demo_…", "symbol": "BTC", "side": "long", "size": 0.1,      "entryPrice": 64000, "exitPrice": 64500, "realizedPnL": 50,      "leverage": 5, "orderType": "market", "fee": 5.78,      "entryTimestamp": "2026-07-01T12:00:00.000Z", "createdAt": "2026-07-01T12:30:00.000Z"    }  ]}

realizedPnL is gross and fee is the round-trip total (the open fee plus the close fee), so this trade netted 50 - 5.78 = 44.22. See Trading for the rates and why a narrow bracket loses money on every outcome.

orderType tells your agent why a position closed - useful when something closed that your agent did not close itself:

ValueMeaning
marketClosed by you (/sandbox/positions/close), by a flip to the opposite side, by a drawdown liquidation, or by the automatic pass when equity net of close fees reached your target.
take_profitYour take-profit level was crossed and fired.
stop_lossYour stop-loss level was crossed and fired.

Triggers are evaluated when you read your account or positions, so exitPrice is the mark at that moment, not the level you set - see Trading.

History is capped, and an idle sandbox expires

Your sandbox keeps the most recent 500 closed trades and drops the oldest as new ones arrive. A sandbox with no writes for 30 days is deleted outright, history included, and the next call starts a fresh account. A long-running agent should persist anything it wants to keep rather than treat this endpoint as a permanent ledger.