Skip to main content
There is no statement endpoint. Stableyard records movements; a statement is a document you assemble, date and own, because its period, boundary, presentation currency and rounding are your decisions. These reads authenticate with your app credentials, so a statement is assembled in your backend. A customer’s browser cannot build one.

Build it from four reads

GET /v2/accounts/{accountId}/balances is not a closing balance. It reports custodyScope: "not_a_custody_balance" and can stay positive after value has left, so use it to sanity-check your totals, never as a figure on the document. See Transactions.

Give each line five things

Each transaction row already carries them:
  • Direction from that account’s point of view, read from perspective.direction.
  • Amount and asset, as an atomic string plus asset.decimals.
  • What produced it, from sourceType and sourceId, with paymentId when it belongs to a Payment.
  • Which leg it is, from financialLegKind, so collection, settlement and fee do not collapse into one figure.
  • Status, so a pending line is not presented as settled.
Fees arrive as their own rows with sourceType: "fee". Keep them as separate lines: a finance team needs gross, fee and net to tie out independently. offrampDetails is frozen at quote time and already redacts bank account numbers to their last four characters, which makes it safe to put in front of a customer. Fields the provider did not return are null, so render an absence rather than an empty string. A txHash can be null while a transfer is unconfirmed: print the line without it rather than holding the statement. Fee amounts come from the Payment’s fees snapshot. Print them only when fees.pricingStatus is quoted; under quote_pending the amounts are still null, and fees itself can be null where the terms are not yours to read. A genuine zero comes back as an explicit 0, and an absent fee is not a free movement. Reconcile against the snapshot, not your current rates.

Do the arithmetic in integers

Amounts are exact atomic strings. Do the arithmetic in integers, scale by asset.decimals once, and format at the edge; a statement that totals in floating point will disagree with itself. Totals are per chain and asset. There is no cross-chain total in the API, and producing one means choosing rates, which is your policy. The only rate Stableyard freezes is on a payout, in offrampDetails.exchangeRate; it values that one movement, so do not reuse it for other lines.

Bound a period from your own store

The transaction list has no from or to, ordering is newest first, and the cursor is opaque. You cannot ask for March.
1

Capture continuously, do not query retrospectively

Read transactions on a schedule, and again when a webhook prompts you, and write each row into your own store keyed on its id. Periods then close against your store.
2

Date each line from dated evidence, not from when you read it

Use the Payment’s createdAt, acceptedAt or succeededAt, a Refund’s createdAt, broadcastAt or confirmedAt, or the createdAt on a ledger entry from the transaction detail read.
3

Pick one date per line kind and keep it

A statement whose lines are dated inconsistently cannot be reconciled against itself, and the inconsistency only shows up at a period boundary.
4

Record the boundary with the statement

Store the exact instant and timezone the period closed on. Every later question about a line near the edge is answered by that value.
A row whose status is not yet terminal at the boundary belongs on the statement as pending, or not at all. Choose one rule and apply it to every period.

Never rewrite a closed statement

A transaction can become reversed, a settled deposit can become reversed, and a delivered payout can be returned downstream. Issue each correction as its own line in the open period, referencing the original line and the statement it came from. statusVersion on a Payment tells you whether your stored copy is stale. operationalState tells you a movement stopped for review without its financial result changing, which is exactly where a statement would otherwise drift. A webhook is the prompt to re-read, never the change itself.

Next: Reconciliation

Match Stableyard records to your own.