Balances

Query wallet activity and holdings. The modern activity feed (paginated, stateless) plus the legacy balance endpoint for available-funds checks.

Two ways to read what a wallet holds and what's happened to it:

  1. The activity feed — a unified, paginated list of every event on the wallet (payments + on-chain messages), newest first. This is the modern consumer-app pattern; it's what you render in a transactions list / history pane.
  2. The legacy balance endpoint — a REST query that returns private / public / locked balances by asset. Still works, useful for "available funds" UI and "validate before submit" guards.

Activity feed (the modern way)

walletFlow.activity merges the bitemporal payments store with the messages table for a single wallet, sorted by timestamp DESC. Use it for any "list the wallet's history" surface — pagination is opaque and stateless, so every replica produces the same page for the same (walletId, limit, cursor) triple.

WALLET_ID=$(curl -s $YF_AUTH/protected/jwt -H "Authorization: Bearer $TOKEN" | jq -r .default_wallet_id)

curl -X POST $YF_GATEWAY/graphql \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query Activity($walletId: String!, $limit: Int, $cursor: String) {
      walletFlow {
        activity(walletId: $walletId, limit: $limit, cursor: $cursor) {
          nextCursor
          items {
            __typename
            ... on PaymentActivity { timestamp payment { id status amount assetId } }
            ... on MessageActivity { timestamp message { id messageType status executed } }
          }
        }
      }
    }",
    "variables": { "walletId": "'$WALLET_ID'", "limit": 25 }
  }'

Pagination contract

  • cursor is opaque. Don't parse it. Pass nextCursor from the previous page back as the next cursor.
  • nextCursor: null means the feed is exhausted — stop.
  • limit defaults to 25, clamped to 200.
  • The same (walletId, limit, cursor) triple returns the same page regardless of which replica answers (stateless, no sticky sessions).
  • Sorted timestamp DESC across both streams; ties break by id lexicographically — stable but arbitrary across __typename.

Legacy balance endpoint

For "available funds" checks and pre-mutation validation. Returns settled + pending balances for a single asset.

curl -X GET "$YF_PAYMENTS/balance?denomination=aud-token-asset" \
  -H "Authorization: Bearer $TOKEN"

Response fields

Field
private_balance
Meaning
Encrypted balance (ZK-proof protected).
Field
public_balance
Meaning
Transparent balance.
Field
locked_out
Meaning
Outgoing pending payments — you've sent, recipient hasn't accepted yet.
Field
locked_in
Meaning
Incoming pending payments — sent to you, awaiting your accept.
Field
outstanding
Meaning
Total locked in your outgoing payments (sum of locked_out).

Computing available balance

available = private_balance - outstanding

Incoming locked_in payments don't affect your balance until the recipient-side flow reconciles them — that's the point of the locked-then-accept shape. The asset is still held by the chain, not yet credited to your account.

Filtering by obligor

Filter to balances arising from obligations issued by a specific party.

curl -X GET "$YF_PAYMENTS/balance?denomination=aud-token-asset&obligor=issuer@example.com" \
  -H "Authorization: Bearer $TOKEN"

Group balances via delegation

When the JWT is a delegation token (acting_as = group_id), the balance query returns the group's holdings:

curl -X GET "$YF_PAYMENTS/balance?denomination=aud-token-asset" \
  -H "Authorization: Bearer $DELEGATION_TOKEN"

Position-based queries (cross-subgraph)

For more structured reads — every position the wallet holds, with the underlying asset metadata joined in — query the federation gateway:

curl -X POST $YF_GATEWAY/graphql \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query($id: String!) { walletFlow { wallet(id: $id) { id positions { id assetId quantity asset { name } } } } }",
    "variables": { "id": "'$WALLET_ID'" }
  }'

Each Position row is a holding of a specific asset; quantity is the wallet's per-asset position. Cryptographic gate: per-entity DEK means a caller can only decrypt positions for wallets they actually hold the signing key for — querying someone else's wallet returns an empty positions array even if the wallet exists.

See also

YieldFabric docs(317)