Skip to main content

Availability

Ledger APIs are available on all plans. Historical retention, query limits, and rate limits may vary by pricing tier.

Intended Purpose

The Anthid Ledger provides a durable historical record of trading activity across connected broker accounts. Rather than querying broker APIs directly for historical orders and positions, applications can use the Ledger APIs to access normalized, broker-agnostic records stored by Anthid. The Ledger is designed for historical analysis, reporting, auditing, monitoring, and application state reconstruction. It is also where completed intents live. The Intents API serves live intents, the ones still open to a replace or a cancel; once an intent fills, is cancelled or is rejected, its full instruction chain moves here, where it is retained for six years with the attribution that a supervisory review needs. Current account state is also available through dedicated latest-state endpoints and real-time streaming APIs.

Access

Ledger endpoints read data for the authenticated user or API-key principal’s organization. API-key callers need organization intent read permission; user callers need an organization admin, member, or read-only role. When a request supplies an account filter, the trading account must belong to the caller’s organization. Account filters are named account_id on every Ledger endpoint.

environment is required

Every Ledger endpoint that reads a set of records requires an environment query parameter. It is not optional and it has no default. Omitting it returns 400.
The parameter resolves to the organization’s accounts in that environment, including accounts that are disabled and accounts that have been deleted. A deleted account keeps its records, so an order placed on an account the organization has since removed still appears in the environment it was placed in. Paper and live are never mixed in one response. A dashboard showing both has to make two requests.
Two endpoints do not take environment, because neither reads a set: GET /v1/orders/{order_id} resolves one order by id, and GET /v1/platform/latency reports the platform rather than your organization.

Endpoint Groups

Current and historical list endpoints support pagination with next_cursor and limit, plus sorting with sort_by and sort_direction. limit defaults to 100 and is capped at 1000. Send a response’s non-null next_cursor value unchanged on the next request.

Filters

Order endpoints can filter by account_id, symbol, intent id, and external broker order id. Historical order endpoints also support start and end time ranges. Position endpoints can filter by account_id and symbol. Historical position endpoints also support start and end time ranges. Order stats require a trailing days value, clamped to 1 through 90, and can optionally filter by account_id. Historical intent endpoints can filter by account_id, symbol, intent id and terminal status, over a start and end range. terminal_only=true returns one row per intent instead of one per action. Intent stats take the same trailing days value as order stats, so the two can be reported side by side over one window. Intent stats count distinct intents rather than actions, so an order amended twice counts once. Symbols are normalized to uppercase, and a blank symbol is treated as no filter rather than as an empty symbol. Where a request reaches back further than the caller’s plan allows, start is raised to the window the plan grants rather than refused.

Analytics endpoints

Beyond the record itself, the Ledger serves aggregates built over it. All of them require environment. A days window of 1 is reported as 24 hourly buckets; anything above that is reported daily. Every window is clamped again to the span the caller’s plan grants. A few behaviors are worth knowing before plotting any of these. Percentiles are null for a bucket with no samples rather than zero, because a bucket in which nothing filled has no time to fill. Exposure reports levels, not flows. A position is carried across buckets the broker did not restate it in, so a quiet stretch repeats the preceding level instead of reading as flat. Daily returns are realized only. A position counts on the day it is closed, against the average cost of what opened it, so opening a position reports a trade with no return against it. Order health limits stuck orders to transitional statuses on purpose. A resting good-till-cancelled limit is open for days by design and is not stuck. stuck_minutes defaults to 15.

Order stats series

Order stats return counts for the whole window at the top level, a data array breaking the same counts down over time, oldest bucket first, and a previous object holding the same totals for the window immediately before this one. Every bucket in the window is present even when no orders landed in it, so the series can be plotted without filling gaps. The window is aligned to bucket boundaries, which makes the newest bucket the hour or day currently in progress. Each timestamp is the RFC 3339 start of its bucket, and the top-level counts are the sum of the buckets.
previous covers the window of equal length immediately before the reported one: the 24 hours before the reported 24, the 7 days before the reported 7. It is the baseline a period-over-period change is measured against.
Use previous rather than deriving a comparison from data. Splitting data in half only ever compares the window against itself, which reports a quiet second half as a fall even when the window matches the one before it.

Order identifiers

Every order carries a platform identifier and, once the broker acknowledges it, the broker’s own. external_order_id is nullable. An order Anthid sent but the broker has not yet acknowledged has a platform identifier and no broker one, and an order the broker rejected outright may never receive a broker identifier at all. Use order_id within Anthid and external_order_id when reconciling against anything outside it. Both are queryable filters.

Order state and status

Each order carries order_status, the detailed lifecycle position in the venue’s vocabulary, and order_state, a coarse rollup derived from it. order_state is computed from order_status rather than reported separately, so the two cannot disagree.
The two fields do not share a casing. order_state serializes as Open, Closed, Rejected, Unspecified. order_status beside it serializes as NEW, FILLED, PARTIALLY_FILLED. Comparing an order_state against "OPEN" never matches.
PARTIALLY_FILLED is Open, and Closed is not a synonym for filled. An order with fills against it is still working; closing it out in your own model on the first fill strands the remainder. A cancelled order and a fully filled order are both Closed.filled_quantity is the only field that reports how much traded, and it is meaningful at every state: partial on an open order, complete on a filled one, and zero on a cancelled one that never traded. Do not infer execution from order_state.

Order fields

Position fields

Position records are relayed from the broker rather than derived from observed fills, so received_at is the age of the information rather than the age of the holding. See Positions for why that choice was made.
Positions are reported for Lightspeed Connect accounts. The Alpaca integration does not yet report holdings, so position endpoints return nothing for an Alpaca account. See Alpaca.

Reconciling after a stream disconnect

Reconnecting to the stream does not replay what was missed while the connection was down. After a disconnect, read the current endpoints rather than assuming continuity: GET /v1/orders and GET /v1/positions return the latest known state per order and per symbol, which is what closes the gap. Both need environment, and a client watching both paper and live has to reconcile each separately.
See the Stream overview for the reconnection pattern.

Common Use Cases

  • Retrieve historical order activity.
  • Retrieve historical position snapshots.
  • Retrieve latest known orders and positions.
  • Query aggregate order counts over a trailing day window, hour by hour or day by day.
  • Build trading dashboards and reporting systems.
  • Audit account activity across broker integrations.
  • Reconstruct application state from historical records.
  • Analyze execution activity over time.
  • Export trading data for compliance or operational review.
  • Power internal analytics and monitoring workflows.

Data Model

The Ledger stores broker activity as normalized platform records. Records are organized around:
  • Orders
  • Positions
Data is indexed and queryable by organization, environment, trading account, symbol, time range, intent id, and external broker order id where supported. Historical records are immutable and intended to represent the broker activity observed by Anthid at the time it occurred.

Historical vs Latest Data

Anthid provides two categories of data access:

Historical

Historical endpoints return records across a specified time range and are intended for reporting, auditing, analytics, and data export workflows.

Latest

Latest endpoints return the most recent known state for orders and positions and are intended for dashboards, account views, and operational workflows. Applications should generally use latest endpoints for current state and historical endpoints for analysis and reporting.

Support

For questions about authentication, request formats, or API behavior, contact support@anthid.com.