Live trading API
Trade today's session: orders, positions, idempotency.
Live trading is paper-trading today's session against the real-time market. You open a session on a live_sim account and use the same session-scoped order, position, and transaction endpoints that practice sessions use — only the path prefix differs (/accounts/{id}/sessions/{sid}/… here, /practice/sessions/{sid}/… for a trading day). Live sessions add dry-run and cancel/replace (PUT), which practice does not have. See Live trading for the concepts and Accounts & sessions for the full account/session API. Requires a registered account.
Open a live session
Create a live_sim account once, then open today's session on it with an empty body:
# create the account (one-time)
curl -s https://api.0dtespx.com/accounts \
-X POST -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"Live paper","engine":"live_sim","starting_capital":"100000"}'
# open today's session
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions \
-X POST -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{}'
The session opens at the latest tick with the account's carried cash balance (you don't pass a starting capital — that's the account's). It is gated on market hours and fresh market data: outside those, you get 400. Re-requesting today's session while it's open returns the open session (200). Find the open session any time with GET /accounts/{id}/sessions/current (or null when none is open).
Session-scoped order endpoints
These are the live-account paths — the same order/position/transaction shapes as a practice session, plus dry-run and cancel/replace:
| Method | Path | Purpose |
|---|---|---|
POST |
/accounts/{id}/sessions/{sid}/orders |
Place an order |
POST |
/accounts/{id}/sessions/{sid}/orders/dry-run |
Validate + preview without persisting |
PUT |
/accounts/{id}/sessions/{sid}/orders/{orderId} |
Atomically cancel + replace a pending limit order |
DELETE |
/accounts/{id}/sessions/{sid}/orders/{orderId} |
Cancel a pending order |
GET |
/accounts/{id}/sessions/{sid}/orders · …/orders/{orderId} |
List / get orders |
GET |
/accounts/{id}/sessions/{sid}/positions |
Current positions |
GET |
/accounts/{id}/sessions/{sid}/transactions |
Transaction log |
GET |
/accounts/{id}/sessions/{sid}/history |
Per-second P&L history (chart line) |
Place an order
The request body matches the orders API. On a live session, two additions make retries safe:
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders \
-X POST -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-H 'Idempotency-Key: ord-2025-05-07-001' \
-d '{
"type":"limit","price":"5.00","price_effect":"debit",
"legs":[{"instrument":"SPXW 260507C05950000","quantity":"1","action":"buy to open"}]
}'
Idempotency-Key(header, optional but recommended) — scoped per session. A duplicate submission within the retention window returns the original response instead of placing a second order. The same key under a different account/session mints a distinct order.client_order_id(body, optional UUID) — used as the order's id; a replay with the same id resolves to the existing order. When omitted, one is derived from the idempotency key, so most clients never need to set it.
Live orders enforce the same trading rules as practice, at the exchange:
- 0DTE SPX index options only. Every leg must be a 0DTE cash-settled SPX index option; an equity, ETF, non-SPX, or non-0DTE leg is rejected with
400 only 0DTE SPX index options can be traded(and the more specificonly SPX index options can be traded …/only 0DTE options …). - Defined-risk only — no naked shorts. An order whose resulting position would hold an uncovered short option is rejected with
400 naked short positions are not allowed, regardless of capital, checked before the buying-power gate. Cover the short with a long of the same type to make it a spread. Unlike practice rejections (JSON{"message": …}), the exchange relays live rejection text as a plain-text body — the message string is the same.
Order lifecycle
Live orders never time-travel — status is the persisted state and stays terminal once set:
| Status | Meaning |
|---|---|
pending |
Accepted, awaiting a matching tick |
filled |
Executed |
canceled |
You canceled the pending order |
expired |
Auto-expired at the 4:00 PM ET close |
rejected |
Failed a buying-power recheck at fill time (rejection_reason explains) |
No orders are accepted after the close (400).
Cancel and replace
# cancel a pending order
curl -s -X DELETE https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders/$ORDER_ID -H "Authorization: $TOKEN"
# atomically cancel + replace a pending LIMIT order's price
curl -s -X PUT https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders/$ORDER_ID \
-H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{"price":"5.50","price_effect":"debit"}'
Only price and price_effect may change in a replacement; type, legs, and underlying are fixed. Cancelling or replacing a non-pending order returns 409. Replacing a non-limit order returns 400.
Read your state
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/current -H "Authorization: $TOKEN" # the open session
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders -H "Authorization: $TOKEN" # orders
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/positions -H "Authorization: $TOKEN" # positions
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/history -H "Authorization: $TOKEN" # per-second P&L history
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/transactions -H "Authorization: $TOKEN" # transactions
Live state also pushes over the WebSocket — REST is authoritative for an operation you just performed; the WebSocket is the source of truth for changes you didn't initiate (other tabs, fills, the close). De-dupe orders by id and prefer the newer updated_at. After a disconnect, refetch positions/orders/transactions to recover.
Settlement and ending
Settlement runs automatically once the closing tick arrives; the session's status becomes settled, its closing balance carries into the account's cash_balance, and GET /accounts/{id}/sessions/current returns null. A live session that has traded cannot be deleted (409 session_traded) — it settles at the close. A live session with no orders can be abandoned with DELETE …/sessions/{sid}, after which you can open a fresh session the same day.
Error semantics
| Status | Meaning |
|---|---|
400 |
Validation error — market closed, non-0DTE-SPX leg, naked short, insufficient quantity to close, or insufficient buying power. Live rejection bodies are plain text (not the JSON envelope). |
409 |
Order is no longer pending, or the session cannot be deleted because it has traded |
503 |
Live trading briefly unavailable — always safe to retry; no state changed |