Ledger reports show amounts separately for each asset. Each row carries
asset_id, asset_symbol, and scale, and Scrip never sums values across assets.
Liability
Outstanding liability is the value participants and groups currently hold. This is the number that belongs on a balance sheet.
Because the ledger is immutable,
as_of queries are stable: ask for June 30 in July, or in December, and get the same answer. Close your books against this number and every other report reconciles back to it.
Liability rollforward
The rollforward explains a period: opening balance, every movement decomposed into named categories, closing balance.closing - opening. There is no residual bucket, and unclassifiable activity fails the request rather than misstating the report.
A typical close: run liability at from and to, run the rollforward for the window, and verify that opening plus the itemized lines equals closing for each asset. This is the artifact to hand an auditor.
Participant rollforward
The same report for one participant. For each asset the participant has used byto, it returns the opening balance, the closing balance, and how the balance changed, split into named amounts.
from and to are required. Both bounds are inclusive and select entries by posting time, the same way statements do. The response repeats from and to exactly as you sent them, including fractional seconds, so a request made with the returned values gives the same figures. Pass asset_id to return one asset. There is no program_id filter. Balances are per asset, not per program, and include AVAILABLE, HELD, and DEFERRED together.
Each amount is called a line. The table shows what each line counts and which action_type creates it:
For every row:
issuance_returns. It does not count as issued and then returned. A settlement for the full pending amount changes nothing and appears in no line. To see the rows behind a figure, run the statement for the same window and use its action_type, rule_id, and reference_id fields to classify them.
Redemption attribution
For sharedLOT-mode assets, break gross redemptions down by the program that issued the consumed value and the program used as the redemption channel:
program_id to filter by redemption channel or asset_id to select one LOT-mode asset. The report is gross and does not net reversals. It does not allocate reversals back to issuer/channel cells. Use liability rollforward, ledger summary, redemption records, or journal entries for reversal-aware financial reporting. SIMPLE-mode assets do not carry the lot lineage required for issuer attribution.
See Multi-Program Balances for how this report differs from ordinary per-program liability and activity views.
Expiration schedule
ForLOT-mode assets, project when outstanding value expires:
never_expiring, expiring_before_window (past expires_at but not yet removed by expiration processing, so still liability), and expiring_after_window figures. Together they sum exactly to total_outstanding. Held and deferred lots are included, since they still expire.
Use this for breakage estimation and forecasting how much value expires in the next 30, 60, or 90 days. See Lots & Expiration for the underlying lifecycle.
Ledger integrity
Verify the ledger is internally consistent and tamper-free:chain_head hash. Pin that hash externally at each close; because every entry’s hash depends on all prior entries, any later alteration of history becomes detectable against your pinned value. See the Ledger guide for how the hash chain works.
Statements
Statements give a bank-statement view with running balances, for support tooling, end-user receipts, or per-account audits:asset_id is required, since a running balance only makes sense within one asset. Pass bucket to limit rows and balances to one or more buckets, such as bucket=AVAILABLE,DEFERRED. The balances cover the selected buckets together.
A card program can report spendable value and value that is still maturing (AVAILABLE plus DEFERRED) as of a billing cycle close in one call. Set to to the close time. GET /v1/participants/{id}/balances returns only the current balance, so it cannot give that figure for a past moment.
Classifying rows
Three fields on every row tell you what it is. You do not need to fetch the journal entry.
Start with
action_type. Then use rule_id and event_id to separate rule-driven movement from manual and system activity. Then group related rows by reference_id. For a rewards summary over a period (earned, redeemed, reversed, expired), use the participant rollforward instead. It returns those figures directly.
Window boundaries
from and to select rows by created_at. Both bounds are inclusive. opening_balance adds up every posting before from, and closing_balance adds up every posting through to. For any window:
closing_balance equals the account’s balance as of to. Paging does not change the running balance.
from and to accept fractional seconds. to=2026-03-31T23:59:59.999Z closes a month without catching the first posting of the next one. Timestamps in the response are whole seconds, and several postings can share one second. Do not reuse a row’s created_at as the next window’s boundary. To continue a long statement, use the cursor from pagination.
When a statement is final
A row can appear up to a few seconds after itscreated_at. Wait at least a minute after to before treating a statement as final. A statement you fetch sooner can gain a row when you fetch it again.
Posting time, not event time
Statements use posting time: the posting’screated_at, which is when the ledger recorded it. For a row created by an event, that is when the event was processed. It is later than the event’s own created_at and is never the event’s event_timestamp.
There is no way to select statement rows by event_timestamp. You set event_timestamp on each event, and events can arrive out of order. Lot spending, holds, settlements, and expirations happen in posting order, so a balance built from event times would not match the ledger. For a customer-facing statement, show event_timestamp as the transaction date next to the posting date. See Timestamps for how the two timestamps relate.
Reading a HELD statement
A statement with bucket=HELD shows value entering and leaving HELD. Each row’s action_type tells you why:
A settlement is a
CREDIT entry with a negative HELD posting, so it appears as a negative CREDIT row with the same reference_id as the authorization credit. See Settlement journal entry and Ledger entries.
For raw movement lists without running balances, the activity endpoints remain available: GET /v1/participants/{id}/activity/history and GET /v1/programs/{id}/history, including dual time filters (from/to on record time, event_from/event_to on event time).
Ledger summary
Per-asset totals and flows for dashboards:
Both filters are optional and combinable. Add
from/to for a per-asset period rollforward (opening, flows, closing). Period redemption figures are gross, so a reversal after the window closes doesn’t rewrite history; all-time figures are net of reversals.
The ledger summary’s period view includes an
other_adjustments_net residual. For audit work, prefer the liability rollforward, which decomposes every movement with no residual.Program activity
Compare programs, or fetch one program’s scorecard:
Use
since to exclude dormant programs. Prefer the by_asset rows over the top-level totals for any program with more than one asset, since the top-level figures sum across assets.
Fulfillment cost
Use the fulfillment-cost report to track gift-card orders and their costs. Results are grouped by program, order status, and currency. Amounts are in currency minor units, such as cents for USD. Use ledger reports to track the asset balances spent on those cards.program_id to report on one program. See Get fulfillment cost report for the returned fields.
Journal entries
The journal is the full audit trail. Every aggregate above traces down to these rows. Each entry is an atomic set of postings (debits and credits) that balance to zero.GET /v1/journal-entries, and fetch one entry with all its postings and its entry_hash with GET /v1/journal-entries/{id}. For the full filter reference (program, entity, asset, bucket, action_type, reference_id, time and amount ranges) and entry detail semantics, see the Ledger guide.