Tradovate API
The /v1/api/tv surface exposes your linked Tradovate accounts through CrossTrade. It is separate from the NinjaTrader /v1/api surface:
| Platform | Route prefix | Runtime | WebSocket |
|---|---|---|---|
| Tradovate | /v1/api/tv | Server-side against your linked Tradovate identity. NT8 can be closed. | Not currently available. |
| NinjaTrader 8 | /v1/api | Through the CrossTrade Add-On in a running NT8 desktop instance. | Supported. |
Most Tradovate endpoints mirror an existing NinjaTrader endpoint. Those shared endpoints are documented on their existing reference pages, where a Tradovate tab sits beside the NT8 tab (for example POST Place Order, GET All Orders, and POST Close Position).
The pages in this Tradovate section are the endpoints unique to Tradovate, with no NT8 equivalent: link status, cash balances, margin snapshots, contract lookup and suggestions, recent fills, and the exchange list.
The two tables below index the whole surface, shared and Tradovate-only, in one place.
Tradovate reads return account state such as positions, orders, fills, and balances. Mutations such as place, cancel, change, close, flatten, and reverse run server-side through the same validation and controls as a Tradovate webhook signal: field validation, Account Manager kill or closing-only checks, position gates, and Trade Copier fan-out all apply. Because these are direct REST calls rather than inbound webhook alerts, the webhook-only layers do not apply: there is no webhook secret or channel to validate, no Alert History entry, no news lockout, no webhook rate bucket, and no per-account/instrument webhook lock.
Tradovate-native REST routing, the API Playground, and MCP Tv_* tools are generally available. CrossTrade-exclusive ATM breakeven and profit-triggered trail activation remain beta.
Native Tradovate vs. CrossTrade-exclusive
| Capability | Owner |
|---|---|
| Market/limit/stop/MIT/trailing orders, OSO/OCO brackets, multibracket targets and stops, continuous ATM trailing | Tradovate native |
| Reusable named Tradovate ATM configurations | CrossTrade webhook configuration; REST and MCP use inline atm* fields |
| Profit-triggered trail activation and durable restart replay | CrossTrade-exclusive until conversion, then handed to a native Tradovate trailing stop |
| Target-fill breakeven | CrossTrade-exclusive; Tradovate AutoBracket has no breakeven field |
| Relative-price conversion, position marks, and managed trigger prices | Calculated by CrossTrade server-side from live market data |
CrossTrade does not use Tradovate market-data entitlements for quote-dependent behavior. It also does not fall back to one user's Add-On cache or direct GetQuote. No fresh pricing means fail closed; for a pending managed trail, the native fixed stop remains active.
Prerequisites
- Link a Tradovate account. Connect at least one Tradovate identity under My Account, Brokers tab. Requests for an unlinked user return
403 tradovate_not_linked. - API access on your plan. The same plan gate as
/v1/apiapplies. Requests without it return401 api_requires_pro. - A bearer token. Use the same token as the rest of the CrossTrade API. See Authentication.
Base URL and auth
All paths are under https://app.crosstrade.io. Every request carries a bearer token:
| Name | Value |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <token> |
The {account} path segment is the Tradovate account name (for example DEMO12345678), matched case-insensitively.
Response envelope
Most reads return {"success": true, "data": ...}. The accounts snapshot is the exception: it returns its snapshot object directly, including success, accounts, asOf, and counts. Mutations return the dispatcher envelope:
{
"success": true,
"destination": "tradovate",
"api": "place_order",
"account": "DEMO12345678",
"instrument": "MES1!",
"response": { "orderId": 123456789 },
"durationMs": 214
}
Validation and account-lock failures use {"success": false, "error": "<message>"}. Failures after dispatch begins may also include dispatcher context such as destination, api, account, instrument, and durationMs. These failures use a 400 status unless an authentication or rate-limit status below applies.
Read endpoints
Shared endpoints link to their NinjaTrader twin page, which carries a Tradovate section. Tradovate-only endpoints link to their own pages.
| Method | Path | Description |
|---|---|---|
GET | /v1/api/tv/status | Token and connection status for your Tradovate identities. |
GET | /v1/api/tv/accounts | List your linked Tradovate accounts. |
GET | /v1/api/tv/accounts/snapshot | Live per-account P&L, positions, and working orders in one call. |
GET | /v1/api/tv/accounts/{account} | One account plus a cash-balance snapshot. |
GET | /v1/api/tv/positions | Open positions across all linked accounts. |
GET | /v1/api/tv/accounts/{account}/positions | Open positions on one account. |
GET | /v1/api/tv/accounts/{account}/position?instrument= | Single net position for one account and instrument. netPos is signed; 0 means flat. |
GET | /v1/api/tv/orders | Every order across all linked accounts. |
GET | /v1/api/tv/accounts/{account}/orders | Working orders on one account. |
GET | /v1/api/tv/accounts/{account}/orders/{id} | One order by Tradovate order id. |
GET | /v1/api/tv/accounts/{account}/orders/{id}/status | Slim order status: id, status, action, contract, timestamp. |
GET | /v1/api/tv/accounts/{account}/orders/{id}/lifecycle | Order audit trail: order, version, commands, and command reports (with reject reasons). |
GET | /v1/api/tv/fills | Recent fills across linked accounts. |
GET | /v1/api/tv/fills/order/{orderId} | Fills for one Tradovate order id. |
GET | /v1/api/tv/accounts/{account}/fills | Recent fills for one account's identity. |
GET | /v1/api/tv/accounts/{account}/watermarks | P&L high-water marks tracked by the Account Manager monitor engine. |
GET | /v1/api/tv/cashbalances | Cash-balance snapshots. |
GET | /v1/api/tv/marginsnapshots | Margin snapshots. |
GET | /v1/api/tv/contracts/find?name= | Resolve a contract by exact symbol. |
GET | /v1/api/tv/contracts/suggest?text= | Contract search suggestions; resolves the active front month. |
GET | /v1/api/tv/exchanges | Exchange reference list. |
Trading endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/api/tv/accounts/{account}/orders/place | Place an order, including native OSO/OCO and multibracket orders plus CrossTrade-exclusive managed ATM enhancements. |
POST | /v1/api/tv/accounts/{account}/orders/{id}/cancel | Cancel one order. |
PUT | /v1/api/tv/accounts/{account}/orders/{id}/change | Change one order. Supports partial changes with required live fields restored before submission. POST is still accepted for backward compatibility. |
POST | /v1/api/tv/accounts/{account}/orders/{id}/replace | Durably cancel and replace one order on the same account and contract. |
POST | /v1/api/tv/accounts/{account}/orders/cancel | Cancel working orders on the account. |
POST | /v1/api/tv/orders/cancelall | Cancel all working orders. |
POST | /v1/api/tv/accounts/{account}/orders/cancel_and_bracket | Cancel working orders, then protect the current position with a bracket. action is the protected position side. The hyphen form cancel-and-bracket is also accepted. |
POST | /v1/api/tv/accounts/{account}/orders/flatplace | Flatten the position and clear same-contract working orders, confirm settlement, then place a new order. |
POST | /v1/api/tv/accounts/{account}/positions/close | Close a position, full or partial by qty or percent. |
POST | /v1/api/tv/accounts/{account}/positions/flatten | Flatten one account. |
POST | /v1/api/tv/positions/flatten | Flatten every linked account. |
POST | /v1/api/tv/accounts/{account}/positions/reverse | Reverse the position. |
POST | /v1/api/tv/accounts/{account}/positions/reverseposition | Reverse the position (position-scoped variant). |
MCP tools
Elite subscribers can call this same surface through the hosted MCP server as Tv_* tools. Reads map to the endpoints above (for example Tv_ListAccounts, Tv_AccountSnapshot, Tv_GetPosition), and trades (for example Tv_PlaceOrder, Tv_ClosePosition, Tv_FlattenEverything) run through the same validation and controls, so Account Manager locks and Trade Copier fan-out apply there too. See Tradovate MCP tools.
Request fields
Mutation bodies use camelCase JSON keys, matching the NinjaTrader REST surface. The command and account come from the path, so a body only needs the trade fields. Common fields:
| Field | Example | Notes |
|---|---|---|
instrument | MES1! | Symbol. Continuous (MES1!), NT8 expiry (MES 09-26), or Tradovate contract (MESU6) forms are accepted. |
action | buy / sell | Order side. |
qty | 1 | Quantity. quantity is also accepted. |
orderType | market / limit / stop | Required for entry endpoints. Stop-limit, MIT, and trailing variants are also supported. |
limitPrice | 5000.25 | Required for limit orders. |
stopPrice | 4995.00 | Required for stop orders. |
takeProfit | 5020.00 | Optional absolute bracket target. REST does not run webhook relative-price preprocessing. |
stopLoss | 4990.00 | Optional absolute bracket stop. REST does not run webhook relative-price preprocessing. |
atmTargets | 20,40 | Tradovate native: per-tier target distances, in ticks by default or points with pt. |
atmStops | 15 | Tradovate native: one stop distance for all tiers or one per tier. |
atmQtys | 1,1 | Tradovate native: contracts per tier; must sum to qty. |
atmTrail | false,true | Tradovate native without a trigger: continuously trail selected tiers from entry. |
atmTrailTrigger | ,30 | CrossTrade-exclusive: profit distance, based on CrossTrade's own live pricing, that activates selected trailing tiers. Pair with atmTrailOffset. Day entries only. |
atmTrailOffset | ,10 | CrossTrade-managed activation, native handoff: native trail distance after confirmed conversion. |
atmBreakeven | 1 | CrossTrade-exclusive: target tier whose fill moves surviving stops to breakeven. Day entries only. |
atmBreakevenOffset | 2 | CrossTrade-exclusive: ticks or points past entry for the managed breakeven stop. |
percent | 0.5 | For positions/close, close half. Must be greater than 0 and at most 1. |
outOfSync | wait | With Strategy Sync, wait withholds this request's entry and returns. It never queues the order for later placement. |
See Destinations for Tradovate-specific requirements and guarantees. Shared field names do not imply identical broker sequencing.
Mutation safety
CANCELREPLACEis owner-fenced and durable. Concurrent operations on the same order are serialized, and staged recovery state is persisted before each broker mutation. The original order must belong to the{account}in the path, and the replacementinstrumentmust resolve to the same exact contract. CrossTrade confirms the leader cancellation and every mapped signal-copier follower cancellation before replacement fan-out. If a cancel or placement outcome is ambiguous, CrossTrade does not resend it and returnsreconciliation_required; reconcile the broker orders before starting a different replacement.- Partial
CHANGErequests restore broker-required fields. When omitted, CrossTrade reads and restores quantity, order type, the limit and/or stop price required by the final order type, and the trailing offset required by trailing orders. Copied followers restore those fields from each follower's own live order version before their modify request. CANCELANDBRACKETprotects an existing side.action=buymeans the live position being protected is long;action=sellmeans it is short. It is not the side of the exit orders. A flat position or side mismatch is rejected before cancellation.FLATPLACEfails closed on settlement. The entry is sent only after the same account and contract report a flat position and no nonterminal working orders. A timeout returns an error without placing the entry; mapped followers run their own settlement barrier.
Example: place a market order
POST /v1/api/tv/accounts/DEMO12345678/orders/place
TOKEN="my-secret-token"
curl -X POST "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"instrument": "MES1!", "action": "buy", "qty": 1, "orderType": "market"}'
A limit order with a bracket looks like this:
curl -X POST "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"instrument": "MES1!", "action": "buy", "qty": 2, "orderType": "limit", "limitPrice": 5000.25, "takeProfit": 5020.00, "stopLoss": 4990.00}'
A two-tier native multibracket with a CrossTrade-exclusive triggered runner:
curl -X POST "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"instrument":"MES1!","action":"buy","qty":2,"orderType":"market","tif":"day","atmTargets":"20,40","atmStops":"15","atmQtys":"1,1","atmTrail":"false,true","atmTrailTrigger":",30","atmTrailOffset":",10"}'
Tradovate hosts the entry, targets, fixed stops, and OCO structure. CrossTrade records the highs and lows of its own live pricing and activates the runner only after the 30-tick trigger. The fixed stop remains active until CrossTrade confirms conversion to a native Tradovate trailing stop.
Locks and trade copier
Because mutations flow through the same validation and controls as a webhook signal, two behaviors are shared:
- Account locks apply. If the Tradovate Account Manager (or a manual switch) has locked the account, a blocked request returns
{"success": false, "error": "Signal blocked, kill switch engaged ..."}. A closing-only lock rejects opening orders unless they carry flatten-first semantics. - Copiers fan out. If a signal-mode Trade Copier is configured on the account as a leader, an order placed here mirrors to its followers, exactly as a webhook would.
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | tradovate_rejected | Tradovate rejected the request (invalid price, insufficient funds, and similar). detail carries the broker's reason. |
| 401 | invalid_bearer | Missing or invalid token. |
| 401 | inactive_subscription | Subscription is not active. |
| 401 | api_requires_pro | Your plan does not include API access. |
| 403 | tradovate_not_linked | No linked Tradovate identity on your account. |
| 403 | endpoint_not_available | Path is not part of the current /v1/api/tv surface. |
| 409 | account_ambiguous | The account name exists on more than one linked identity. Rename one so every linked account name is unique. |
| 429 | rate_limited | CrossTrade API request budget exceeded (180 requests/min per user). Includes a Retry-After header and retryAfter body field. |
| 429 | broker_rate_limited | Tradovate's own rate-limit penalty is active on your linked identity. A passthrough of the broker's limit, not a CrossTrade limit. Includes Retry-After and retryAfter. |
| 429 | egress_limited | Response egress budget exceeded. |
| 500 | internal_error | Unexpected server error. Safe to retry once; contact support if it persists. |
| 502 | tradovate_session_expired | Your Tradovate session expired. Reconnect the account under My Account, Brokers. |
| 502 | tradovate_unavailable | Tradovate did not respond or returned a server error. Retry shortly. |
| 503 | temporarily_disabled | The Tradovate API is paused by a kill switch. |
The two 429 codes are deliberately distinct: rate_limited means your integration exceeded CrossTrade's own request budget (see Rate Limiting), while broker_rate_limited means Tradovate itself has imposed a penalty window on your linked identity and CrossTrade is holding requests back until it clears. Both include a Retry-After header with seconds to wait. Mutations blocked by a broker penalty return broker_rate_limited along with the usual dispatcher context fields (destination, api, account, instrument, durationMs).
Limitations
- Trades placed manually inside the Tradovate app are not seen by this API and are not blocked by account locks. The Account Manager can still flatten after the fact.
- Enforcement and live data run server-side, so flatten and lock latency is measured in seconds, not milliseconds.
- Account names use realistic placeholders in this doc (
DEMO12345678). Use your own account names.