As-of-ledger & staleness
Reason about data freshness with meta.last_indexed_ledger, pin reads to a past ledger with as_of_ledger, and pull history over a ledger range.
Because Orion stores per-ledger snapshots of every entity, a read isn’t only “the latest state” — you can ask what a wallet looked like at an exact point in chain history, and reconstruct a range as a time series. Both build on one primitive: the ledger sequence number.
Freshness: meta.last_indexed_ledger
Every response carries a meta block describing how fresh the data is and, for
a point-in-time read, which ledger it was actually served as of. This is the
block from a read pinned with ?as_of_ledger=64019174:
"meta": {
"ledger_lag_seconds": 6,
"data_staleness_seconds": 6,
"oracle_staleness_seconds": null,
"last_indexed_ledger": 64166899,
"requested_ledger": 64019174,
"as_of_ledger": 64019136,
"partial_result": false,
"sources": ["soroban_rpc"],
"attribution_confidence": null,
"response_time_ms": 18
}| Field | Meaning |
|---|---|
ledger_lag_seconds | How far behind the present the served data is: the seconds between the newest indexed ledger and now, measured rather than assumed. A large value means indexing has stalled and everything served is that far out of date. null when there is nothing to measure it from. |
data_staleness_seconds | Deprecated alias of ledger_lag_seconds, carrying the same value. Prefer ledger_lag_seconds; the alias will be removed once clients have moved. |
oracle_staleness_seconds | Age of the oldest price behind the USD values on the unified positions read. null when no price age was measured, which includes the per-protocol point-in-time reads. |
last_indexed_ledger | The newest ledger the index has reached. The anchor for “how current is this?” |
requested_ledger | The ledger you pinned with as_of_ledger, echoed back unchanged. null when the request carried no pin. |
as_of_ledger | The ledger the read was actually served as of: the latest stored snapshot at or before requested_ledger, not an echo of it. A snapshot is stored when a position changes, so a position that has not moved is served from its last snapshot and this value can sit well below the pin — months of ledgers is normal. null when there was no pin, when the endpoint does not support one, or when no snapshot exists at or before the pin (the data comes back empty, never as current state). |
partial_result | true when the response is incomplete — for example, a position that could not be priced. |
sources | The data source(s) that served the response. |
attribution_confidence | Deprecated and always null. It carries no measurement and has no replacement; judge a response by sources, partial_result and ledger_lag_seconds. |
response_time_ms | Time spent building the response, in milliseconds. |
Use last_indexed_ledger, not the wall clock, as your notion of “now” — two
responses with the same value describe the same chain state.
Point-in-time reads: as_of_ledger
Protocol-scoped position endpoints accept an as_of_ledger query parameter and
return the wallet’s state at that ledger — the latest stored snapshot at or before
it. The values were computed then, so the health factor and USD values you get
back are the ones that were true at that ledger, not today’s numbers recomputed
against old balances.
curl "https://mainnet.g.orionhq.run/v1/users/GCHAIE7BKB2EWTPQG2RWI3IQIALHUKP2LPAZZFG3STLXRUD37PZ7WEUZ/positions/blend?as_of_ledger=58414509" \
-H "x-orion-token: $ORION_KEY"as_of_ledger is supported on the per-protocol reads (/positions/blend,
/positions/aquarius, /positions/soroswap, /positions/{protocol}), on
protocol reserves and tvl, on the history endpoints, and on the activity feed.
Note. The unified
GET /v1/users/{address}/positionsendpoint does not serveas_of_ledger— the parameter is rejected there. For a point-in-time portfolio, read per-protocol.
History over a ledger range
The Blend summary-history endpoint returns the account’s value and health as a
series across a ledger window. Pass from_ledger and to_ledger for the raw
snapshots in range:
curl "https://mainnet.g.orionhq.run/v1/users/GCHAIE7BKB2EWTPQG2RWI3IQIALHUKP2LPAZZFG3STLXRUD37PZ7WEUZ/positions/blend/summary/history?from_ledger=58000000&to_ledger=64166899" \
-H "x-orion-token: $ORION_KEY"{
"data": {
"address": "GCHAIE7BKB2EWTPQG2RWI3IQIALHUKP2LPAZZFG3STLXRUD37PZ7WEUZ",
"points": [
{
"ledger": 3300000,
"timestamp": "2026-07-18T08:00:00Z",
"supplied_usd": "1580.00",
"borrowed_usd": "140.00",
"health_factor": "1.79",
"borrow_limit_pct": "0.14"
},
{
"ledger": 3356416,
"timestamp": "2026-07-23T09:12:44Z",
"supplied_usd": "1620.00",
"borrowed_usd": "137.45",
"health_factor": "1.87",
"borrow_limit_pct": "0.13"
}
]
},
"meta": { "...": "response metadata" }
}Each point’s valuation fields are read straight from the stored snapshot at that ledger — never re-priced or re-derived.
Bucketing a range
Raw snapshots can be dense. History endpoints bucket the series two ways; pick one axis per request:
- Ledger buckets — set
ledger_bucketto a bucket size withfrom_ledger/to_ledger. Buckets are cut on the ledger axis. - Time buckets — set
interval(1h,4h, or1d) withfrom/toISO-8601 timestamps. Buckets are cut on the wall-clock axis.
The Blend and Aquarius pool-history endpoints also accept a range shortcut that
implies both a window and an interval:
range | Window | Bucket |
|---|---|---|
24h | last 24 hours | 1h |
7d | last 7 days | 4h |
30d | last 30 days | 1d |
curl "https://mainnet.g.orionhq.run/v1/users/GCHAIE7BKB2EWTPQG2RWI3IQIALHUKP2LPAZZFG3STLXRUD37PZ7WEUZ/positions/blend/CCCCIQSDILITHMM7PBSLVDT5MISSY7R26MNZXCX4H7J5JQ5FPIYOGYFS/history?range=7d" \
-H "x-orion-token: $ORION_KEY"Gaps
A bucket with no snapshot is a real gap, and fill controls how it’s rendered:
fill | Behavior |
|---|---|
none | Leave the gap empty (the default). |
locf | Last-observation-carried-forward — repeat the previous known snapshot. |
An locf bucket that precedes the account’s first-ever snapshot has nothing to
carry forward: its ledger and value fields come back null rather than a
fabricated zero. fill requires an active bucketed mode.
Positions concepts
The unified position model — buckets, health factor, borrow limit, liquidation price, USD value, and why they are stored, not derived at read time.
Protocol coverage & registry
Which Stellar DeFi protocols Orion supports, what "supported" means, and the registry endpoints for reserves, TVL, and emissions.