Skip to content
Skip to main content

Trading API FAQs

Answers to the most common questions about the TradeZero Trading API. For detailed technical documentation, see the relevant reference page linked in each answer.


Orders

Why does my order return 200 OK but orderStatus: "Rejected"?

The API gateway returns 200 OK once the request is structurally valid. Whether the order is accepted by the matching engine is a separate outcome reflected in orderStatus. The most common engine rejections are:

  • R78 - market order submitted outside Regular Trading Hours (9:30 AM-4:00 PM ET). Use a Limit order with timeInForce: "Day_Plus" or "GTC_Plus" for extended hours.
  • R95 - you tried to open both a long and a short on the same symbol at the same time. Cancel one direction first.
  • R114 - clientOrderId was already used in this session. Generate a fresh unique value for every order - ids are not reusable after cancellation.

Always read orderStatus after a 200 response. See Validation errors.


Can I modify a working order?

There is no modify endpoint. Use the cancel-then-replace pattern: DELETE /v1/api/accounts/{accountId}/orders/{clientOrderId} the original, wait for orderStatus: "Canceled", then POST /order a replacement with a new clientOrderId. Reusing the original id returns R114 even after cancellation - the id is consumed permanently the moment it is first accepted. See Modifying an order.


What's the difference between GET /orders and GET /orders/start-date?

Both are about orders, but they sit at different levels:

  • GET /orders is the today's order book - it returns every order on the account from today's session regardless of current state (rows include New, Accepted, PartiallyFilled, Filled, Canceled, Rejected, DoneForDay, …) plus any still-working orders from previous sessions (multi-day GoodTillCancel / GTC_Plus that haven't filled or expired yet). Each row carries clientOrderId directly, plus order-level fields (orderStatus, executed, priceAvg, limitPrice, timeInForce, …). Use this to manage live orders and to read terminal-state outcomes for orders submitted today.
  • GET /orders/start-date/{date} is the historical orders archive - up to one week of post-trade history. Rows are at the fill level, not the order level: each row is one execution (tradeId, qty, price, commission, totalFees, grossProceeds, netProceeds, tradeDate), and a partial-filled order produces multiple rows. There is no clientOrderId and no orderStatus on these rows. Use this for daily P&L recaps, fee/commission rollups, and reconciliation. Paper accounts have no order history available and always return { "orders": [] }.

Why does canceling an order return 404, 400, or 401?

DELETE /v1/api/accounts/{accountId}/orders/{clientOrderId} has three distinct failure shapes:

  • 401 Unauthorized (JSON) - auth headers were missing. Body: {"statusCode":"Unauthorized","message":"Token not provided","detail":null}.
  • 404 Not found (plain text) - the gateway couldn't find the order (wrong ID, not yet registered, wrong account, auth mismatch with valid-looking headers, or the order is already in a terminal state such as Filled, Canceled, or Rejected).
  • 400 with JSON body ({"statusCode":"BadRequest","message":"CancelOrderWithResponse","detail":"ASLib Unable to fetch account orders..."}) - the accountId in the URL path belongs to a different customer.

In all cases, confirm the final state via GET /orders. See Cancel behavior.


Does cancel-all work when there are no open orders?

Yes. DELETE /v1/api/accounts/orders always returns {"message":"Cancel Request Submitted Successfully"} as long as the multipart body carries a valid account field - regardless of whether any orders were open.


Are enum values case-sensitive?

Yes, but enforcement differs by field. side, orderType, securityType, and timeInForce are schema-validated - wrong case returns 400. openClose is handled at the engine level: sending "open" instead of "Open" returns HTTP 200 with orderStatus: "Rejected". Always send "Open" or "Close" exactly. See Validation errors.


Can I send fractional shares?

No. orderQuantity must be a whole integer. Sending 0.5 returns 400 Bad Request with - orderQuantity: Invalid type. Expected: integer, given: number.


What is route: "<no value>" in a rejected order?

When an order is rejected before it reaches a route (schema error or engine rejection), the route field surfaces as the literal string "<no value>". This is expected behavior for rejected orders.


Which routes are available - and what's the difference between paper and live?

Query GET /v1/api/accounts/{accountId}/routes:

  • Paper accounts return two synthetic routes - PAPER (Stock + Option) with Day, GoodTillCancel, GoodTillCrossing and PAPERM (MLEG, Day-only).
  • Live accounts typically return five real routes - SMART (smart router for Stocks; widest order-type and TIF set), CTDL (direct-access stock route), SMARTO (smart router for single-leg Options), SMARTM (smart router for multi-leg Options), and ARCA (direct ECN route for Stocks; adds IOC and FOK TIFs).

The exact set on a given live account depends on subscription. Always query /routes and use what the API returns - don't hard-code. See Get available routes for the field-level breakdown.


Can I cancel an order immediately after placing it?

A DELETE /v1/api/accounts/{accountId}/orders/{clientOrderId} issued before the gateway has fully registered the placement may return 404 Not found. Allow at least 250-500 ms between POST /order and the cancel attempt, or wait until the order appears in GET /orders first.


Accounts & Authentication

How do I tell paper accounts from live accounts in the API response?

Read the accountType field from GET /v1/api/account/{accountId}. Paper accounts return "Paper"; live accounts return "Live" (or another non-"Paper" value reflecting how the account is classified). Do not pattern-match account IDs - use the server-issued field. See Account Types.


Why am I getting 404 Not found instead of 401 Unauthorized when my credentials are wrong?

The Accounts and Orders GET endpoints return 404 Not found for auth failures intentionally - this prevents account ID enumeration by hiding the distinction between a bad credential and an unknown path. The DELETE /v1/api/accounts/{accountId}/orders/{clientOrderId} endpoint is the exception and does return 401. See Error handling.


Do I need to refresh or rotate my API keys?

No automatic expiry - keys stay valid until you explicitly regenerate or disable them in the portal. Rotate if you suspect a leak: use Regenerate Secret to replace just the secret (invalidating the old one immediately) or Disable + Generate for a full key replacement. Every lifecycle event is logged in the portal's Audit Trail and triggers an email. See Key lifecycle rules.


Short Locates

Why does POST /quote return 200 OK but no offer ever appears in /history?

On paper accounts, /quote accepts the call but immediately writes a Rejected row to /history (locateStatus: 56). Locates are live-only - paper accounts cannot produce inventory. See Account Types.

On live accounts, quotes that find no available inventory may produce a Rejected row with text: "No shares available." rather than an Offered row.


How long does an offered locate quote stay valid?

30 seconds from when the row first reaches locateStatus: 65 (Offered). If you don't POST /accept within that window, both rows (and the .SU sibling for Reg SHO symbols) move to status 67 (Expired) and you need to issue a fresh /quote.


What is a Reg SHO threshold security and why do I see two rows in /history?

A Reg SHO threshold security is a stock with five or more consecutive settlement days of excessive fails-to-deliver. The platform returns two priced rows for these symbols: one for the Pre-Borrow offer (your original quoteReqID) and one for the cheaper Single Use offer (quoteReqID + ".SU"). Accept either one - accepting the other auto-expires. See Short Locates.


WebSocket

Do the streams send a keepalive ping?

No. The server does not send a keepalive. Implement your own reconnection logic with exponential backoff so long-lived connections can recover automatically if they drop. See Reconnection.

Are both streams available on paper accounts?

Yes. The P&L and Portfolio streams work identically on paper and live accounts. P&L updates are driven by simulated quote ticks on your paper positions. See WebSocket API.