Skip to main content
Snapshots answer “what did this address hold, or who held this token, at ledger N?”. Use them for airdrop lists, audits, and reconciling a past report. There are two ways: add as_of_ledger to a holdings or holders read for recent ledgers (instant), or start a snapshot job for any ledger (seconds to minutes). Both run on Testnet. On Mainnet, as_of_ledger reads and snapshot jobs answer 501 not_implemented; read the current state there. Set these once in your terminal. The sample values are real Testnet data, so the read examples return real results.

Pick a valid ledger

Balance history begins at read_view.bootstrap_ledger (Testnet: 5253887), so an older ledger such as 1234567 returns 409 on an as_of_ledger read. The newest ledgers are written in 64-ledger batches (about five minutes), so stay at least that far behind read_view.as_of_ledger. This picks a ledger about 80 minutes ago:

Recent history: as_of_ledger

Trimmed holdings response at a past ledger:
The answer is the state after that ledger, and read_view.as_of_ledger echoes it. History stores balances only, so at a past ledger:
  • account, limit, the liabilities and authorized are null.
  • spendable is null on every record, XLM and trustlines alike, because it needs the reserve, liabilities and authorization of that ledger.
  • as_of_closed_at is null. Holders carry holder_count at that ledger, but supply is null (the supply_source field still names the current source and does not apply).
  • include=closed and simulated balances are not supported, and publishable keys get 403.
  • Holders refuse assets with more than 100,000 current holders (409); use a snapshot job.
On Testnet, as_of_ledger reads are free (one request toward the daily Testnet cap each). The Mainnet weight is 5 credits per started 100 records.

Any past ledger: snapshot jobs

A job computes holdings of one address or holders of one asset at any ledger from 63 up to the latest applied ledger. This example uses Testnet USDC (2,116 holders at ledger 1234567, which is before the balance history). It needs jq and uuidgen:
POST /snapshots answers 202 with Location: /snapshots/{id} and the job in status queued. A completed job (live, trimmed to 1 of 2,116 records):

Request

Result

status moves from queued to running to completed (with result) or failed (with error). Jobs run one at a time, and an organization can have up to 5 jobs queued or running.

Credits

On Testnet a job is free and counts as one request toward the daily Testnet cap. The Mainnet price is 50 credits, charged when the job completes and released when it fails. Polling GET /snapshots/{id} is free. Publishable keys cannot start or read jobs.

Errors

See errors and idempotency.

Next