Orders API
Place, preview, and cancel orders, including multi-leg.
Orders open and close positions in a trading session. The endpoints have the same shape on both surfaces — an account-less practice session (/practice/sessions/{sid}/orders) and a live session under an account (/accounts/{id}/sessions/{sid}/orders) — so the request/response bodies below apply to both; only the path prefix differs (live sessions additionally offer dry-run and PUT replace, which practice does not). This page covers placing, previewing, inspecting, replacing, and canceling them. For the concepts — order types, fill rules, SPX ticks — see Orders & order types.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/accounts/{id}/sessions/{sid}/orders |
List orders |
POST |
/accounts/{id}/sessions/{sid}/orders |
Place an order |
POST |
/accounts/{id}/sessions/{sid}/orders/dry-run |
Validate + preview without persisting |
GET |
/accounts/{id}/sessions/{sid}/orders/{orderId} |
Get one order |
PUT |
/accounts/{id}/sessions/{sid}/orders/{orderId} |
Replace a resting limit order's price |
DELETE |
/accounts/{id}/sessions/{sid}/orders/{orderId} |
Cancel/delete an order |
Instrument strings
Legs name instruments by string:
| Type | Format | Example |
|---|---|---|
| Equity | <SYMBOL> |
SPX |
| Equity option | <ROOT><YYMMDD><C|P><strike×1000, 8-digit> (21-char OSI) |
SPXW 250115C05950000 |
The equity-option string is canonical OPRA/OSI: a 6-char root left-justified and space-padded, the YYMMDD expiry date, a C or P side letter, and the strike × 1000 zero-padded to 8 digits. SPX 0DTE options use the SPXW weekly root (so SPXW followed by two spaces). An option is identified by root + date + side + strike; the session-close time is implied, not encoded.
Place an order
A limit debit call vertical (buy the 5950 call, sell the 5970 call) — multi-leg orders must be limit:
curl -s https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders \
-X POST -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{
"type": "limit",
"price": "10.50",
"price_effect": "debit",
"legs": [
{"instrument":"SPXW 250115C05950000","quantity":"1","action":"buy to open"},
{"instrument":"SPXW 250115C05970000","quantity":"1","action":"sell to open"}
]
}'
The response includes the computed fill_price, fill_datetime, status, per-leg transactions, fees, and a buying-power-effect block projecting the impact on margin and available buying power:
{
"id": "a7e2c9d1-…",
"type": "limit",
"price": "10.50",
"price_effect": "debit",
"status": "filled",
"fill_price": "10.45",
"fill_price_effect": "debit",
"execution_price": "10.50",
"fees": "3.44",
"legs": [ … ],
"transactions": [ … ],
"buying-power-effect": {
"change-in-buying-power": "108.44",
"change-in-buying-power-effect": "Debit",
"new-buying-power": "99891.56"
}
}
A single-leg market order fills immediately at the natural price (ask for a buy, bid for a sell); market and stop orders must be single-leg.
Limit and stop orders
Add price for a limit and stop_trigger for a stop, plus a price_effect of debit or credit. Slippage is not a request field — it is a single per-account setting (in Settings → Simulator Costs, defaulting to $0.05 on new accounts) that the server applies to limit/stop fills, and is echoed back on the order's slippage/execution_price — see Slippage:
{"type":"limit","price":"1.50","price_effect":"credit","legs":[ … ]}
{"type":"stop","stop_trigger":"12.00","price_effect":"debit","legs":[ /* single leg */ ]}
On a practice session, a non-marketable limit comes back pending; advance the session clock past its fill_datetime and it shows filled. On a live session it stays pending until a matching tick arrives. A stop that would trigger immediately is rejected with 400.
Validation order
Checks run in this order, each with its own 400:
- Order type and leg shape parse;
marketandstoporders must be single-leg. Every leg must be a 0DTE SPX index option (only 0DTE SPX index options can be traded). pricerequired forlimit,stop_triggerforstop,price_effectfor both. (Slippage is taken from your account setting, not the request body.)- SPX option tick rules — single-leg < $3 → $0.05, ≥ $3 → $0.10, multi-leg → $0.05.
- A limit
pricecan't exceed the structural maximum profit of the legs. - Market data must exist for every leg at the current time.
- A stop can't already be triggered.
- Available-to-close: a
to closeleg can't exceed the quantity you hold (insufficient quantity to close). - Defined-risk only: the resulting position can't hold an uncovered short option (
naked short positions are not allowed) — checked before buying power, so a naked-adding order returns this, not a buying-power error, regardless of capital. - Buying-power check, including all existing pending orders.
Rejections are JSON {"message": …} on practice sessions. The naked-short and available-to-close checks read your resulting book (current filled + pending positions plus the new order's legs), so they also block stripping the long leg out of a spread you already hold.
Dry-run
POST /accounts/{id}/sessions/{sid}/orders/dry-run runs every validation and returns the same response (minus transactions) without persisting anything — no order, no trades, no history change. It returns 200 instead of 201. Use it for pre-trade confirmation; a successful dry-run strongly implies the real POST will succeed too. (On a live session the result is advisory — the market may move between the dry-run and the real place.)
Order status and fees
On a historical session, order status is computed from fill_datetime versus the session's current clock time — filled if the fill is at or before now, otherwise pending; rewind the clock and a filled order can revert to pending. On a live session, status is the persisted lifecycle state (pending, filled, canceled, expired, rejected) and never time-travels. Fees follow suit: a filled order reports the actual summed fees; a pending order shows a schedule-based estimate. See Fees.
Replace
curl -s -X PUT https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders/$ORDER \
-H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{"price":"10.40","price_effect":"debit"}'
Only price and price_effect may change — type, legs, and underlying are fixed. On a live session this is an atomic cancel + replace. Replacing a non-limit order returns 400; replacing a non-pending order returns 409.
Cancel
curl -s -X DELETE https://api.0dtespx.com/accounts/$ACCT/sessions/$SID/orders/$ORDER -H "Authorization: $TOKEN"
Returns 204. On a practice session, deletion removes the order and its trades (including any settlement trades it affected) and recomputes history. On a live session it cancels the pending order; cancelling a non-pending order returns 409.
For today's session, see the live trading API — the same paths, with idempotency keys scoped per session.