Order Rejections
When the order engine declines an order, the outcome is HTTP 200 with orderStatus: "Rejected" — never a dedicated rejection HTTP status. The human-readable reason lives in text.
Full integration guide
This page is a quick reference. For polling cadence, WebSocket pushes, code samples, and troubleshooting, see Order rejections in the Equity Trading guide.
Golden rules
- Never trust
POST /orderalone — live routed orders may returnPendingNew+text: nullbefore rejecting ~50 ms later. - Always read
clientOrderIdfrom the POST response — R118 with route may rewrite the ID with anINVALIDsuffix. - Poll
GET /order/{clientOrderId}and fall back toGET /orderswhen single-order lookup returns404. - Never cancel a
Rejectedorder — cancel returnsHTTP 200but overwritestextwith R130, masking the real reason.
Where rejection reasons appear
| Surface | Use when |
|---|---|
POST /order | Immediate ack; may be PendingNew without text |
GET /order/{clientOrderId} | Authoritative single-order lookup — poll every 50 ms |
GET /orders | Full book; only surface for some R118 + route cases |
Portfolio WebSocket Order | Real-time; subscribe before placing orders |
Rejection code reference
Common codes on live accounts:
| Code | Example text | Typical trigger | POST timing |
|---|---|---|---|
| R24 | R24: Your order cannot have a STOP price of Zero | Stop/StopLimit without valid stopPrice | Async |
| R54 | R54: Unable to reach the destination Route | Invalid or missing route | Async |
| R78 | R78: Market orders are not allowed at this time | Market order outside RTH (9:30 AM–4:00 PM ET) | Sync outside RTH |
| R95 | R95: Cannot have opening buy and sell orders at the same time | Opening long and short on same symbol | Async (~4 ms) |
| R06 | R06: This symbol is restricted from trading at this price | Limit far from allowed band | Async |
| R114 | R114: Invalid duplicate UserOrderId | Reused clientOrderId in session | Sync |
| R118 | R118: Stop price is on wrong side of quote | Stop on wrong side of quote | Async without route; sync + text: null with route |
| R130 | R130: Cancel Request Rejected: … | Cancel on terminal order (from DELETE, not placement) | — |
| R145 | R145: Negative Price Is Not Allowed | Negative limitPrice or stopPrice | Sync |
| (none) | Rejected: Broker Rejected … | Venue declined (no R## prefix) | Async |
| (none) | null | Risk check with no surfaced code | Sync on POST |
Parse R-codes from text:
const code = order.text?.match(/^(R\d+)/)?.[1] ?? null;
Schema errors vs routing rejections
| Class | HTTP status | Body |
|---|---|---|
| JSON Schema / parse failure | 400 | Plain text (Content-Type: text/plain) |
| Routing / risk rejection | 200 | Order JSON with orderStatus: "Rejected" |
See Validation errors for the 400 table.
Troubleshooting cheatsheet
| Symptom | Likely cause | Fix |
|---|---|---|
POST PendingNew, no error shown | Async rejection | Poll GET /order or use Portfolio WS |
POST Rejected + text: null, GET → 404 | R118 with explicit route | Scan GET /orders; do not cancel |
| Error only after cancel | R130 overwrote original text | Read rejection before cancel |
GET /order 404 once | Registration race | Retry 1–2 s |