> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stableyard.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Transactions

> List and read the ledger rows each payment leg writes, and know why balances are not spendable.

A transaction is the durable record of one financial leg on an account. Payments and deposits are what happen; transactions are what remains, and they are what reconciliation reads.

## Each row names what produced it

`sourceType` names what produced the leg and `sourceId` identifies that object.

| `sourceType` | Produced by |
| - | - |
| `payment` | A canonical Payment, in either direction |
| `deposit` | Funds detected at a deposit address |
| `vault_funding` | A direct transfer into a Vault |
| `fee` | A fee movement, recorded as its own row |
| `refund` | A return of verified funds |
| `adjustment` | An accounting correction |

When the leg belongs to a canonical Payment, `paymentId` carries it and `financialLegKind` says which leg this row is: `collection`, `send_execution`, `settlement`, `fee_payout`, `refund` or `adjustment`. One Payment therefore produces several rows, which is what lets a finance team tie gross, fee and net against each other.

## List an account's transactions

```bash theme={null}
curl "https://staging-api-v2.stableyard.fi/v2/accounts/acct_123/transactions?limit=50" \
  -u "$APP_ID:$APP_SECRET"
```

| Query parameter | Behaviour |
| - | - |
| `limit` | 1 to 100, default 50 |
| `cursor` | The `nextCursor` from the previous page. Stop when `nextCursor` is absent |
| `status` | `pending`, `completed`, `failed` or `reversed` |

Rows come back newest first. There is **no date-range filter**: the list is paged, not queried by period, and [Statements](/payments/statements) covers what to do about that. The cursor is opaque and ordering is stable, so paging a history twice returns the same sequence. Do not construct a cursor or read meaning out of one.

<Note>
  `posted` is a status a row can hold, but it is not accepted by the `status` filter. Filter on the other four, or read every page and select in your own code.
</Note>

## Only pending is non-terminal

| Status | Meaning | Terminal |
| - | - | - |
| `pending` | Recorded, not yet final | No |
| `completed` | The leg completed | **Yes** |
| `posted` | Posted to the financial ledger | **Yes** |
| `failed` | The leg did not complete | **Yes** |
| `reversed` | Corrected by compensating entries | **Yes** |

`reversed` is an accounting correction, not an on-chain clawback. The underlying funds have usually already moved, so do not tell a customer money is coming back.

## Direction belongs to the reader

A transfer between two accounts is one row both sides can read. Read `perspective.direction`, which reports `sent`, `received`, `self` or `related` for the account in the path, with `perspective.counterpartyAccountId` when the other side is known. The same value is repeated at the top level as `direction`.

`amount` is stated from that perspective too. On a send, the sender sees the gross source debit and the recipient sees the net destination amount actually settled, so both sides reconcile without doing the arithmetic.

## What a record contains

Always present: `id`, `accountId`, `status`, `amount`, `description`, `sourceType`, `sourceId`.

| Field | What it is |
| - | - |
| `id` | The `txn_` identifier. Treat it as opaque |
| `amount` | An `asset` and an atomic-units string. Scale by `asset.decimals` to display; never parse it as a floating-point number |
| `description` | A short label, such as `USDC payment` |
| `paymentId` | Set when the leg belongs to a canonical Payment |
| `financialLegKind` | Which leg of that Payment this row is |
| `perspective` | `accountId`, `direction`, and `counterpartyAccountId` when known |
| `sourceTransfer` | Where the value came from: `amount`, plus `txHash`, `logIndex` and `fromAddress` when the leg began on chain |
| `settlement` | The settling transfer's `amount` and `txHash`. The hash can be `null` while it is unconfirmed |
| `offrampDetails` | The frozen quote and recipient for a local-currency payout |

### Off-ramp detail

A payout row carries `offrampDetails`, frozen at quote time and safe to print on a receipt. Account numbers appear as their last four characters only, and any field the provider did not return is `null` rather than absent.

| Field | Contents |
| - | - |
| `country`, `destinationType` | Where it went, and by which kind of destination: `external_qr`, `external_bank` or `bank_account` |
| `fiatAmount` | `amountAtomic`, `assetCode` and `decimals` for the local-currency figure |
| `fundingAmount`, `providerPrincipal` | The stablecoin side of the movement |
| `fees` | `provider`, `platform` and `partner`, each separately |
| `exchangeRate` | `rate`, `baseAssetCode` and `quoteAssetCode`. The direction is preserved |
| `receiver` | `name`, `bankName`, `bankCode` and `accountNumberLast4` |

Account numbers appear as their last four characters only, and any field the provider did not return is `null` rather than absent.

**`fiatAmount.amountAtomic` can be `null`.** When known at snapshot time, it is an exact integer string scaled by the supplied `decimals`; otherwise it is `null`. A `collect_exact` bank payout, for example, records confirmed crypto collection before the final fiat amount exists. `assetCode` and `decimals` are present either way. Show `null` as unavailable, never as zero. Preserve the reported precision: exact-input US bank payout evidence can contain six decimal places of USD.

A completed collection or settlement row describes the crypto leg only. It does not mean the bank payout succeeded, and the frozen snapshot can keep an unknown amount after the payment moves on. For the payout result, read the row's `paymentId` through `GET /v2/payments/{paymentId}`.

## Read one transaction for its ledger entries

```bash theme={null}
curl https://staging-api-v2.stableyard.fi/v2/accounts/acct_123/transactions/txn_123 \
  -u "$APP_ID:$APP_SECRET"
```

The detail read adds `ledgerEntries`: `id`, `direction` (`debit` or `credit`), `amount` and `createdAt`. They are scoped to the account you asked about, so they are that account's side of the entry rather than the full balanced set. `createdAt` on a ledger entry is the one dated field the contract publishes against a movement.

## Balances are reporting, not custody

`GET /v2/accounts/{accountId}/balances` returns an accounting projection over the same recorded activity. It reports `balanceType: "recorded_activity_projection"` and `custodyScope: "not_a_custody_balance"`, and those two fields exist to stop one specific bug.

<Warning>
  Never authorise a spend against it, never gate a withdrawal on it, and never render it as funds available. A sufficient-funds check written against this number passes when it should fail, rarely, in production, on a real customer.
</Warning>

`activityTotals` carries one entry per asset, always per chain and asset rather than one cross-chain figure:

* `netRecordedFlowAtomic` is a **signed** cumulative net. It can be negative when a wallet or Vault funded outside Stableyard's view makes a verified payment, and it can stay positive after value has settled out to a customer's own wallet. Your parser must accept a leading minus sign.
* `reservedForVaultPaymentsAtomic` is context about Vault payments in flight. It is presented alongside the net, never subtracted from it.
* `observedAt` is when the projection last changed, not a heartbeat.

To know what can actually be spent, read the source: the wallet, the escrow, or the Vault's spend usage.

<Card title="Next: Statements" icon="file-invoice" href="/payments/statements">
  Turn these rows into a periodic statement for a customer.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.