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 namedaccount_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 byaccount_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 requireenvironment.
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, adata 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 carriesorder_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.
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.
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