GET Order Lifecycle
- NT8
- Tradovate
Get order lifecycle by ID NT8
Returns the complete lifecycle of a single order: every state transition recorded by the add-on (Submitted, Accepted, Working, PartFilled, Filled, Cancelled, Rejected, and so on), plus every inbound API submission attempt against the order, optionally merged with fills from NT8's in-memory Executions collection. Use this endpoint to reconcile orders end-to-end when a real-time WebSocket event was dropped, arrived out of order, or never made it to your application.
The add-on persists each event to its local SQLite the moment it happens, so the lifecycle is durable even across WebSocket disconnects or transient network failures. Default retention is 90 days.
Endpoint
GET /v1/api/accounts/{account}/orders/{orderId}/lifecycle
Headers
| Name | Value |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <token> |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
account | string | Required | Required by the URL pattern. The add-on does not filter by account, so any name (e.g. Sim101) resolves the same lifecycle. Included for routing symmetry with the other per-order endpoints. |
orderId | string | Required | NT8 OrderId or the original/xt id supplied at placement time. Either resolves correctly. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
includeFills | boolean | Optional | Default true. Merge fill events from NT8's in-memory Executions into the timeline. |
includeRaw | boolean | Optional | Default false. Include the full raw JSON snapshot for each event (verbose). |
limit | int | Optional | Default 200. Cap on rows returned. Server enforces a hard ceiling of 2000. If SQLite already returns limit rows, no fills will be merged. Bump limit if a single order has many lifecycle events and fills are needed. |
Code examples
- Python
- JavaScript
- cURL
import requests
token = 'my-secret-token'
url = "https://app.crosstrade.io/v1/api/accounts/Sim101/orders/50cca7b8051146c684087db511107983/lifecycle"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
params = {
"includeFills": True,
"limit": 200
}
try:
response = requests.get(url, headers=headers, params=params)
print(f"Response Code: {response.status_code}, Response Text: {response.text}")
except Exception as e:
print(f"An error occurred: {e}")
const token = 'my-secret-token';
const params = new URLSearchParams({ includeFills: "true", limit: "200" });
const url = `https://app.crosstrade.io/v1/api/accounts/Sim101/orders/50cca7b8051146c684087db511107983/lifecycle?${params}`;
fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
TOKEN="my-secret-token"
curl -X GET "https://app.crosstrade.io/v1/api/accounts/Sim101/orders/50cca7b8051146c684087db511107983/lifecycle?includeFills=true&limit=200" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
Response
- 200
- 400 - not found
- 400
{
"success": true,
"orderId": "50cca7b8051146c684087db511107983",
"originalOrderId": "myStrat_entry_42",
"account": "Sim101",
"count": 5,
"events": [
{
"timestamp": "2026-05-22T14:30:12.118Z",
"epoch": 1779114612118.0,
"source": "api_received",
"event": "PlaceOrder",
"orderState": null,
"account": "Sim101",
"orderId": "myStrat_entry_42",
"originalOrderId": null,
"correlationId": null,
"filled": null,
"quantity": 1,
"avgFillPrice": null,
"limitPrice": 5235.00,
"stopPrice": null,
"reason": null
},
{
"timestamp": "2026-05-22T14:30:12.214Z",
"epoch": 1779114612214.0,
"source": "order_update",
"event": "Submitted",
"orderState": "Submitted",
"account": "Sim101",
"orderId": "50cca7b8051146c684087db511107983",
"originalOrderId": "myStrat_entry_42",
"correlationId": null,
"filled": 0,
"quantity": 1,
"avgFillPrice": 0.0,
"limitPrice": 5235.00,
"stopPrice": 0.0,
"reason": null
},
{
"timestamp": "2026-05-22T14:30:12.241Z",
"epoch": 1779114612241.0,
"source": "order_update",
"event": "Working",
"orderState": "Working",
"account": "Sim101",
"orderId": "50cca7b8051146c684087db511107983",
"originalOrderId": "myStrat_entry_42",
"correlationId": null,
"filled": 0,
"quantity": 1,
"avgFillPrice": 0.0,
"limitPrice": 5235.00,
"stopPrice": 0.0,
"reason": null
},
{
"timestamp": "2026-05-22T14:31:48.902Z",
"epoch": 1779114708902.0,
"source": "execution",
"event": "Execution",
"orderState": null,
"account": "Sim101",
"orderId": "50cca7b8051146c684087db511107983",
"originalOrderId": "myStrat_entry_42",
"correlationId": null,
"executionId": "abc-exec-1",
"filled": 1,
"quantity": null,
"avgFillPrice": 5235.00,
"limitPrice": null,
"stopPrice": null,
"reason": null
},
{
"timestamp": "2026-05-22T14:31:48.911Z",
"epoch": 1779114708911.0,
"source": "order_update",
"event": "Filled",
"orderState": "Filled",
"account": "Sim101",
"orderId": "50cca7b8051146c684087db511107983",
"originalOrderId": "myStrat_entry_42",
"correlationId": null,
"filled": 1,
"quantity": 1,
"avgFillPrice": 5235.00,
"limitPrice": 5235.00,
"stopPrice": 0.0,
"reason": null
}
]
}
{
"success": false,
"error": "not_found",
"detail": "No lifecycle events found for orderId '50cca7b8051146c684087db511107983'. The order may pre-date v1.13.2 or may not exist on this machine."
}
{
"success": false,
"error": "missing_args",
"detail": "'orderId' is required"
}
Platform nuances
Requires CrossTrade NT8 Add-On v1.13.2 or later. Older add-ons return an "Unknown API command" error. Update from the Add-On Changelog.
Source field
The source column tells you which side of the system emitted the event:
api_received: the add-on accepted an inbound order-mutation API call (PlaceOrder, Cancel, Change, and so on). Captured before the call reaches NT8.api_rejected: the add-on rejected the call before it reached NT8 (validation, missing account, malformed args). Thereasonfield carries the error string.order_update: NT8 fired itsAccount.OrderUpdateevent. TheorderStatefield carries the NT8 state string (Submitted,Working,PartFilled,Filled,Cancelled,Rejected,Expired, etc.).execution: synthesized at read time from NT8's in-memory Executions. Only present whenincludeFills=true.
WebSocket API
This request can also be made over the WebSocket API. Only orderId is required; account and the query parameters are accepted but optional (the add-on does not filter by account).
{
"action": "rpc",
"id": "my-request-id",
"api": "GetOrderLifecycle",
"args": {
"orderId": "50cca7b8051146c684087db511107983",
"includeFills": true
}
}
Get order lifecycle by ID Tradovate
Returns the Tradovate audit trail for one order. No NinjaTrader add-on is involved: the trail is assembled server-side from Tradovate's order, orderVersion, command, and commandReport dependency reads, so it works while NinjaTrader is closed and does not require CrossTrade NT8 Add-On v1.13.2.
Endpoint
GET /v1/api/tv/accounts/{account}/orders/{id}/lifecycle
Headers
| Name | Value |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <token> |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
account | string | Required | Tradovate account name, for example DEMO12345678. |
id | string | Required | Tradovate order id, for example 123456789. |
Code examples
- Python
- JavaScript
- cURL
import requests
token = 'my-secret-token'
url = "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/123456789/lifecycle"
headers = {
"Authorization": f"Bearer {token}"
}
try:
response = requests.get(url, headers=headers)
print(f"Response Code: {response.status_code}, Response Text: {response.text}")
except Exception as e:
print(f"An error occurred: {e}")
const token = 'my-secret-token';
const url = "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/123456789/lifecycle";
fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
TOKEN="my-secret-token"
curl -X GET "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/123456789/lifecycle" \
-H "Authorization: Bearer $TOKEN"
Response
The response uses the Tradovate read envelope. data contains the current order, the highest-id version (quantity, type, and prices), related commands, and reports.
If an optional broker read fails, the endpoint still returns HTTP 200 with success: true, plus top-level partial: true and unavailable. The latter lists the failed sections: version, commands, or reports:<commandId>. An unavailable version becomes {}, unavailable commands become [], and failed report reads are omitted while successful reports remain. These markers are absent when all reads succeed; an empty section marked unavailable is not evidence that no data exists. The order read is mandatory: its failure remains an error, not a partial success.
{
"success": true,
"data": {
"order": {},
"version": {},
"commands": [],
"reports": []
}
}
Platform nuances
- Unlike the NT8 endpoint, there are no
includeFills,includeRaw, orlimitquery parameters. order.ordStatusis Tradovate's status:Suspendedfor a bracket leg that has not been activated yet, thenWorking,Filled,Canceled,Rejected, orExpired.order.ocoId,order.parentId, andorder.linkedIdlink the legs of an OSO/OCO to each other.commandsare the requests submitted against the order. TheNewcommand carries theclOrdIdyou sent (orderIdorclOrdIdon the placement), which is how you match an order back to your own intent id after an ambiguous response. The order row itself does not carry it.- Report rows carry
rejectReasonand human-readabletextfor refused commands. - Tradovate can create an OrderVersion for a command it later rejects. The returned
versionis not proof that a modification took effect; reconcile the corresponding command outcome incommandsandreports. - Order, version, and command reads run concurrently. Report reads then run concurrently, bounded to commands with IDs in the last 10 returned command rows. This cap does not limit the number of report rows returned.
- Fills are not merged into this response. Retrieve them separately from
GET /v1/api/tv/fills/order/{orderId}. - Tradovate uses
{id}for this route; the separate fills route retains{orderId}. {account}is resolved before the reads and scopes all dependency lookups. An unrecognized account returnsunknown_account; a missing order or an order belonging to another account returnsunknown_order.
See the Tradovate API overview for the full route list and error table.