Skip to main content

GET Fill History

Durable fill history Tradovate​

Returns your Tradovate fill history from CrossTrade's durable capture. Unlike /v1/api/tv/fills, which mirrors Tradovate's session-scoped fill list, this endpoint is served from the same durable store that powers the CrossTrade Trade Journal. Successfully captured fills remain available after the daily session reset and over weekends; linking alone does not guarantee complete history.

Use this endpoint for order and fill reconciliation. Rows are returned as a flat list (not per-identity envelopes), oldest first, with cursor pagination.

Coverage

Capture requires an authorized Tradovate link and Tradovate journal import enabled (on by default). It is periodic, not real-time. While CrossTrade has an active user-sync stream for your login, fills schedule a debounced capture pass. Defaults are a 90-second debounce and a 10-minute minimum interval between triggers; ongoing fills can delay the pass further. Otherwise, background maintenance attempts capture during the daily 5-6 p.m. America/New_York window, before the session reset. These are scheduling defaults, not capture deadlines or guarantees. For anything time-sensitive, read /v1/api/tv/fills instead.

Capture reads the visible session, so current-session fills may be included even if they precede linking. Earlier sessions cannot be backfilled through this endpoint. Manual trades and trades placed through other platforms are included when present in that fill stream. Accounts journaled from the CrossTrade NT8 add-on are served by the executions endpoints, not this one.

Endpoint​

GET /v1/api/tv/fills/history

Headers​

NameValue
Content-Typeapplication/json
AuthorizationBearer <token>

Query parameters​

NameTypeRequiredDescription
fromstringOptionalInclusive lower bound, ISO-8601 date or datetime (UTC). Date-only values start at 00:00Z.
tostringOptionalExclusive upper bound, ISO-8601 date or datetime (UTC). Date-only values cover the whole day.
accountstringOptionalFilter to one account by display name, such as DEMO12345678.
environmentstringOptionalFilter to one environment: demo or live.
limitintOptionalMaximum rows per page (1-1000, default 500).
cursorstringOptionalOpaque pagination cursor from the previous page's nextCursor.

Code examples​

import requests

token = 'my-secret-token'

url = "https://app.crosstrade.io/v1/api/tv/fills/history"
params = {"from": "2026-08-01", "to": "2026-08-08", "limit": 500}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}

while True:
response = requests.get(url, params=params, headers=headers)
payload = response.json()
for fill in payload.get("data", []):
print(fill["executionId"], fill["instrument"], fill["action"],
fill["qty"], "@", fill["price"])
cursor = payload.get("nextCursor")
if not cursor:
break
params["cursor"] = cursor

Response​

{
"success": true,
"count": 2,
"nextCursor": null,
"data": [
{
"executionId": "tv:demo:987654321",
"fillId": 987654321,
"orderId": 123456789,
"accountId": 1234567,
"accountName": "DEMO12345678",
"environment": "demo",
"instrument": "MNQ 09-26",
"root": "MNQ",
"action": "Buy",
"qty": 1,
"price": 23150.25,
"commission": 0.35,
"fees": 1.02,
"timestamp": "2026-08-07T14:32:05.184Z",
"tradeDate": "2026-08-07"
},
{
"executionId": "tv:demo:987654400",
"fillId": 987654400,
"orderId": 123456810,
"accountId": 1234567,
"accountName": "DEMO12345678",
"environment": "demo",
"instrument": "MNQ 09-26",
"root": "MNQ",
"action": "Sell",
"qty": 1,
"price": 23162.75,
"commission": 0.35,
"fees": 1.02,
"timestamp": "2026-08-07T15:05:41.020Z",
"tradeDate": "2026-08-07"
}
]
}

executionId is globally unique and stable, so it is the recommended dedup key for reconciliation. fillId and orderId are the raw Tradovate ids, valid within one environment. timestamp is the fill time in UTC; tradeDate is Tradovate's session trade date, which is what daily statements group by. When more rows match than limit, nextCursor carries the position of the last returned row; pass it back as cursor to fetch the next page. A null value for nextCursor means the end of currently stored matching rows, not verified capture completeness.

Platform nuances​

  • This is a CrossTrade-side read. It costs none of your Tradovate API budget and works while markets are closed.
  • Rows are flat and oldest-first; there are no per-identity envelopes. Use the environment and accountName fields (or the query filters) to separate identities.
  • There is no coverage watermark or revision cursor. Re-read overlapping date ranges to discover later captures and fee updates, merging rows by executionId rather than treating every existing row as immutable.
  • Commission and fees reflect captured Tradovate FillFee data, not Journal trade overrides. Missing or failed fee reads preserve previously captured fees on existing fills; new fills receive zero until fee data becomes available. Available FillFee rows update the stored values normally, including genuine zeros. Later sweeps can refresh fees while the fill remains in the live session; post-reset corrections are not automatically backfilled by this endpoint.
  • The account filter matches the display name as it appears in your journal, so accounts that are no longer linked remain queryable.
  • Fills you delete in the Trade Journal are excluded here as well.
  • If you disable Tradovate journal import in your journal settings, capture stops and this endpoint stops accruing new rows.
  • A missed trading day (for example, an expired Tradovate authorization that was not re-linked before the session closed) is a permanent gap in the capture; CrossTrade alerts you when the link needs attention.

Authentication uses the same bearer token as the rest of the CrossTrade API and requires a plan with API access (Pro) plus a linked Tradovate account. Unlinked users receive 403 tradovate_not_linked.

This endpoint is REST-only and has no WebSocket equivalent.