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

# Wallet Balances Stream

> The exact token balances of the wallets you follow, pushed as each transaction changes them, one message per transaction and wallet: one wallet, a list of up to 100, or a watchlist of thousands.

`WS channel: wallet-balances`

The exact token balances of the wallets you follow, pushed as each transaction changes them, with the new balance of every token the transaction moved. Follow one wallet (on one chain or on several), a list of up to 100, or a [watchlist](https://docs.serialized.xyz/endpoints/watchlists.md) of thousands of wallets in one subscription.

Use it for a live holders tab of your own users, balance alerts, or any screen that shows what a large set of wallets holds. For positions with entry price and PnL, see the [Wallet Positions Stream](https://docs.serialized.xyz/streams/wallet-positions-stream.md); for every trade, the [Wallet Trades Stream](https://docs.serialized.xyz/streams/wallet-trades-stream.md).

## Delivery model

* **Events, as they land.** There is no snapshot: the stream starts with the first balance change after your subscription. Take the starting balances from REST: [token holders](https://docs.serialized.xyz/endpoints/token-holders.md) with `watchlist=<id>` for a watchlist, [`/v1/wallet/positions`](https://docs.serialized.xyz/endpoints/wallet-positions) for a wallet.
* **One message per transaction and wallet.** Every message is `"data": [balance, ...]`: the balance after the transaction of each token it moved for that wallet. A transaction that moves 5 tokens of a wallet is one message of 5 balances. When your connection falls behind, the balances waiting for it are merged (the latest per wallet, chain and token): a message can then carry several transactions, and costs 1 per wallet and chain it carries.
* **Absolute balances.** Each balance is the wallet's whole balance of the token after the transaction, never a difference: the latest one replaces what you had.
* **Keep the greatest (`block`, `logIndex`).** For each wallet, chain and token, keep the balance with the greatest `block`, then the greatest `logIndex`. A balance that arrives late, or twice (after a resume), then changes nothing.
* **Tokens.** SPL tokens on Solana and ERC-20 tokens on EVM chains. Native coins (SOL, ETH and the native coin of each chain), their wrapped versions and USD stablecoins are not on this channel: read them with [`/v1/wallet/positions`](https://docs.serialized.xyz/endpoints/wallet-positions) (`includeNative=true`, `includeStables=true`).

## Parameters

Give `address` with either `chain` or `chains`, or give `wallets`, or give `watchlist`.

**chain** `string`

Public chain id, `evm:<id>` or `solana`. Example: `solana`

**chains** `string | string[]`

Several chains of the wallet in one subscription, in place of `chain`: public chain ids, comma-separated (`"evm:8453,evm:1"`) or as an array. `evm` stands for every EVM chain and combines with explicit ids. Every chain must belong to the wallet's family: EVM chains for a hex address, `solana` for a base58 address. Send `chain` or `chains`, not both. Example: `evm`

**address** `string`

The wallet address (EVM hex, case-insensitive; Solana base58). Example: `DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj`

**wallets** `object[]`

A list of 1 to 100 wallets, `[{ "chain": "...", "address": "..." }, ...]`, in place of `chain` and `address`. Each entry takes one chain and counts as one subscription in the limit of your account. Each balance carries its `wallet`.

**watchlist** `string`

The id of one of your [watchlists](https://docs.serialized.xyz/endpoints/watchlists.md), in place of `chain`, `chains`, `address` and `wallets`. Every wallet of the list is followed, and the subscription counts as one in the limit of your account, whatever the size of the list. Wallets you add or remove over REST are followed or dropped within seconds, without subscribing again. Example: `app-holders`

**updatePeriod** `integer`

Milliseconds, 0 to 60000; default `0` (every transaction as it lands, in its own message while your connection keeps up). Above 0, one message per period carries the latest balance of each wallet, chain and token that changed in the period (the greatest `block`, `logIndex`); a period that piles up more than 256 balances, or 256 KB of them, is sent at once and the next period starts, so no balance is left out. The ack carries the value applied (snapped up to `0, 100, 200, 250, 500, 1000, 2000, 5000, 10000, 30000, 60000`). `"block"` is not available on this channel. See [Choosing your pace](https://docs.serialized.xyz/streams/overview.md#choosing-your-pace-updateperiod).

**excludeSpam** `boolean` (default: false)

`true` leaves out the balances of tokens flagged as spam. A token without a spam verdict is delivered. On a list, give it once, next to `wallets`.

## The balance

| Field | |
| - | - |
| `wallet` | The wallet (EVM lowercased, Solana as is) |
| `chain` | Public chain id |
| `token` | The token address (EVM lowercased, the mint on Solana) |
| `rawBalance` | The balance after the transaction, in the token's smallest unit: an exact integer, as a string. Always present |
| `decimals` | The token's decimals, or `null` when not known yet |
| `balance` | `rawBalance` scaled by `decimals`: an exact decimal string, never in exponent notation, the format of `amount` on [`/v1/wallet/positions`](https://docs.serialized.xyz/endpoints/wallet-positions). `null` when `decimals` is `null` |
| `block` | The block (the slot on Solana) |
| `logIndex` | The position of the change in its block: compare it, never read meaning into it |
| `txHash` | The transaction (its signature on Solana) |
| `publishedAt` | When the balance was published on our side, ms, or `null`. Not the block time: to order balances, use `block` and `logIndex` |

Parse `rawBalance` and `balance` with a decimal or big-integer library, not a float, when the last digits matter: an 18-decimal balance does not fit in a float.

## Resume

With a single wallet, on one chain or on several, or a watchlist, every message carries a `cursor`. After a reconnect, subscribe again with `"since": "<cursor of the last message you received>"`: you receive the balance changes after it (up to 5 minutes back), then live. You are never billed twice: anything up to your cursor that comes back is flagged `"replay": true` and free (on a watchlist, this can include a few messages from the seconds around your disconnection); what comes after it is billed like live messages, even when it carries `"replay": true`. Keep the greatest (`block`, `logIndex`) as usual: a balance you already applied changes nothing. On a watchlist, a wallet removed, or the list cleared, while you were away may not be replayed. If the replay is not available, a `REPLAY_TOO_OLD` notice gives `details.restFromMs`: the subscription keeps going; since balances are absolute, read the current ones again over REST ([token holders](https://docs.serialized.xyz/endpoints/token-holders.md) with `watchlist=<id>`, [`/v1/wallet/positions`](https://docs.serialized.xyz/endpoints/wallet-positions)) for the tokens you show.

A message flagged `"gap": true` follows balances that could not be delivered (for example when your connection fell behind): read the current balances over REST for the tokens you show, then keep applying messages.

A `wallets` list takes no `since`: after a reconnect, subscribe again and read the current balances over REST. See [Reconnect & resume](https://docs.serialized.xyz/streams/overview.md#reconnect--resume).

## Billing

**1 credit per wallet and chain in each message**: one transaction of the wallet costs 1 at the default pace, however many of its tokens it moved, and a batch (`updatePeriod`) costs 1 per wallet and chain it carries. A wallet whose balances do not change costs nothing, and the connection is free. A wallet followed on several chains, or a `chains: "evm"` wallet of a watchlist, pays only the chain of each transaction. On a resume you are never billed twice: what comes back up to your cursor is free, and what comes after it is billed like live messages (see [Resume](#resume)). Details in [Billing](https://docs.serialized.xyz/streams/overview.md#billing).

`GET /v1/usage/breakdown` reports this channel under `WS wallet-balances`, where `requests` is the number of billed messages.

## Errors

| Code | Meaning | What to do |
| - | - | - |
| `INVALID_PARAM` | A parameter was refused. `details.param` names it (`chain`, `chains`, `address`, `wallets[3].address`, `watchlist`, `updatePeriod`, `excludeSpam`, `since`) | Fix the subscription |
| `INVALID_CHAIN` | Unknown chain id | Fix the subscription |
| `NOT_FOUND` | The watchlist does not exist (`details.reason`: `unknown`, or `purged` after 48 hours without use). Sent on a `subscribe`, or later when the watchlist is deleted or purged: the subscription ends. `details.purgedAt` comes with `purged` on a `subscribe`; it can be missing when the watchlist is purged while you follow it | Create the watchlist, then subscribe again |
| `RATE_LIMITED` | The subscription limit of your account is reached, or the list does not fit in what is left | Close subscriptions, send a shorter list, or ask us to raise the limit |
| `RATE_LIMITED` with `details.refused` (watchlist, a notice) | Some wallets of the watchlist cannot be followed for now: `details.refused` is how many. The subscription stays open and the other wallets keep coming | Contact us |
| `UPSTREAM_ERROR` with `details.retryAfterMs` | Wallet streams are starting | Send the same `subscribe` again after `details.retryAfterMs` |
| `UPSTREAM_ERROR` with `details.resumes: true` | Live data is temporarily unavailable | Nothing: the subscription resumes by itself |

## Close codes

| Code | Meaning |
| - | - |
| `4401` | Auth - key missing, invalid, or revoked. Live connections are dropped the moment a key is revoked. |
| `4402` | Credits or billing: the WebSocket mirror of REST `402` / `403`. The close reason says what to do (see [Errors](https://docs.serialized.xyz/streams/overview.md#errors)). |
| `1012` | Server restart - reconnect after the `retryAfterMs` of the JSON reason, then subscribe again. |
| `1013` | Server at capacity - reconnect after the `retryAfterMs` of the JSON reason. |
| `1008` | Policy - subscription limits, flooding, or a blocked socket. Fix the cause before reconnecting. |
| `1001` | Nothing received from you for 60 s (idle timeout), or for 35 s while our WebSocket ping waits for its answer (`no answer to pings`). Send a `ping` every 15 to 30 s; after `no answer to pings`, reconnect and resume. |
| `1009` | A frame you sent is over 64 KB. |

```json Subscribe (a watchlist) theme={null}
{
  "op": "subscribe",
  "channel": "wallet-balances",
  "id": "holders-tab",
  "params": {
    "watchlist": "app-holders"
  }
}
```

```json Subscribe (one wallet) theme={null}
{
  "op": "subscribe",
  "channel": "wallet-balances",
  "id": "bal-1",
  "params": {
    "chain": "solana",
    "address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj"
  }
}
```

```json Subscribe (one wallet, every EVM chain) theme={null}
{
  "op": "subscribe",
  "channel": "wallet-balances",
  "id": "bal-evm",
  "params": {
    "chains": "evm",
    "address": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09"
  }
}
```

```json Subscribe (a list, spam left out) theme={null}
{
  "op": "subscribe",
  "channel": "wallet-balances",
  "id": "followed",
  "params": {
    "wallets": [
      { "chain": "solana", "address": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj" },
      { "chain": "evm:8453", "address": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09" }
    ],
    "excludeSpam": true
  }
}
```

```json Ack (a watchlist) theme={null}
{
  "op": "subscribed",
  "id": "holders-tab",
  "channel": "wallet-balances",
  "updatePeriod": 0,
  "watchlist": {
    "id": "app-holders",
    "version": 4183,
    "wallets": 48210
  }
}
```

```json Balances (a watchlist) theme={null}
{
  "op": "event",
  "id": "holders-tab",
  "channel": "wallet-balances",
  "data": [
    {
      "wallet": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj",
      "chain": "solana",
      "token": "CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump",
      "rawBalance": "15915963200000",
      "decimals": 6,
      "balance": "15915963.2",
      "block": 371204455,
      "logIndex": 81592322,
      "txHash": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh",
      "publishedAt": 1790539767391
    }
  ],
  "asOf": 1790539767412,
  "cursor": "v2.muk95908.muk95aov"
}
```

```json Balances (one transaction, two tokens) theme={null}
{
  "op": "event",
  "id": "bal-evm",
  "channel": "wallet-balances",
  "data": [
    {
      "wallet": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09",
      "chain": "evm:8453",
      "token": "0x4ed4e862860bed51a9570b96d89af5e1b0efefed",
      "rawBalance": "0",
      "decimals": 18,
      "balance": "0",
      "block": 49964751,
      "logIndex": 41,
      "txHash": "0x3f1c9a2be7d4405c8e61f0a9b2c7d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
      "publishedAt": 1790539782311
    },
    {
      "wallet": "0x95d955179a7cd45aeef394ed39f6a8d8b1bd1e09",
      "chain": "evm:8453",
      "token": "0xb2000000000000000000007bf6d5cbb0e24cb301",
      "rawBalance": "1113125600000000000000000",
      "decimals": 18,
      "balance": "1113125.6",
      "block": 49964751,
      "logIndex": 49,
      "txHash": "0x3f1c9a2be7d4405c8e61f0a9b2c7d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
      "publishedAt": 1790539782311
    }
  ],
  "asOf": 1790539782377,
  "cursor": "v1.amun6v2l5lbes.2l1.mfq3c9k4"
}
```

```json Watchlist deleted (the subscription ends) theme={null}
{
  "op": "error",
  "id": "holders-tab",
  "error": {
    "code": "NOT_FOUND",
    "message": "Watchlist \"app-holders\" not found",
    "details": {
      "watchlist": "app-holders",
      "reason": "unknown"
    }
  }
}
```


## AsyncAPI

````yaml asyncapi.json wallet-balances
id: wallet-balances
title: Wallet Balances Stream
description: >-
  The exact token balances of the wallets you follow, pushed as each transaction
  changes them, one message per transaction and wallet (merged, the latest per
  wallet, chain and token, when your connection falls behind): one wallet on one
  chain or on several, a list of up to 100, or a watchlist of thousands per
  subscription. No snapshot: take the starting balances from REST
  (`/v1/token/holders` with `watchlist`, `/v1/wallet/positions`). Balances are
  absolute: for each wallet, chain and token, keep the one with the greatest
  (`block`, `logIndex`), and late or repeated balances change nothing. SPL and
  ERC-20 tokens; native coins, their wrapped versions and USD stablecoins are on
  `/v1/wallet/positions`.
servers:
  - id: production
    protocol: wss
    host: ws.serialized.xyz
    bindings: []
    variables: []
address: wallet-balances
parameters: []
bindings: []
operations:
  - &ref_2
    id: subscribe-wallet-balances
    title: Subscribe Wallet Balances Stream
    type: send
    messages:
      - &ref_5
        id: subscribe
        payload:
          - name: Subscribe
            description: Client frame opening the subscription (additive, ack is explicit).
            type: object
            properties:
              - name: op
                type: string
                description: subscribe
                required: true
              - name: channel
                type: string
                description: wallet-balances
                required: true
              - name: id
                type: string
                description: >-
                  Client-chosen subscription id, echoed on every frame of this
                  subscription.
                required: true
              - name: params
                type: object
                required: true
                properties:
                  - name: chain
                    type: string
                    description: >-
                      Public chain id, `evm:<id>` or `solana`. Give `address`
                      with `chain` or `chains`, or give `wallets`, or give
                      `watchlist`.
                    required: false
                  - name: chains
                    type: array
                    description: >-
                      Several chains of the wallet in one subscription, in place
                      of `chain`: public chain ids (a comma-separated string is
                      accepted too). `evm` stands for every EVM chain and
                      combines with explicit ids; no limit on the number of
                      chains. Every chain must belong to the wallet's family
                      (EVM chains for a hex address, `solana` for a base58
                      address). One stream and one cursor for all of them;
                      counts as one subscription. Send `chain` or `chains`, not
                      both.
                    required: false
                    properties:
                      - name: item
                        type: string
                        required: false
                  - name: address
                    type: string
                    description: The wallet address. Required with `chain` or `chains`.
                    required: false
                  - name: wallets
                    type: array
                    description: >-
                      A list of 1 to 100 wallets in place of `chain` and
                      `address`; each entry takes one chain and counts as one
                      subscription, each balance carries its `wallet`. `since`
                      is not available on a list.
                    required: false
                    properties:
                      - name: chain
                        type: string
                        required: true
                      - name: address
                        type: string
                        required: true
                  - name: watchlist
                    type: string
                    description: >-
                      The id of one of your watchlists (`/v1/wallet/watchlist`),
                      in place of `chain`, `chains`, `address` and `wallets`:
                      every wallet of the list is followed, and the subscription
                      counts as one whatever the size of the list. Wallets added
                      or removed over REST are followed or dropped within
                      seconds, without subscribing again. The ack carries
                      `watchlist` (`id`, `version`, `wallets`). When the
                      watchlist is deleted or purged, the subscription receives
                      `NOT_FOUND` and ends. On a watchlist, a `RATE_LIMITED`
                      notice with `details.refused` says how many of its wallets
                      cannot be followed for now; the others keep coming.
                    required: false
                  - name: updatePeriod
                    type: integer
                    description: >-
                      Milliseconds, 0 to 60000, default 0: every transaction as
                      it lands, in its own message (snapped up to 0, 100, 200,
                      250, 500, 1000, 2000, 5000, 10000, 30000, 60000; the ack
                      carries the value applied). Above 0, one message per
                      period carries the latest balance (the greatest `block`,
                      `logIndex`) of each wallet, chain and token that changed
                      in the period; a period that piles up more than 256
                      balances, or 256 KB of them, is sent at once and the next
                      one starts, no balance left out. `"block"` is not
                      available on this channel.
                    required: false
                  - name: excludeSpam
                    type: boolean
                    description: >-
                      `true` leaves out the balances of tokens flagged as spam;
                      a token without a spam verdict is delivered. On a list,
                      once, next to `wallets`.
                    required: false
              - name: since
                type: string
                description: >-
                  Optional, next to `params`, one wallet (on one chain or
                  several) or a watchlist: the `cursor` of the last message you
                  received. You get every balance change after it (up to 5
                  minutes back, flagged `"replay": true`: keep the greatest
                  (`block`, `logIndex`) and they change nothing), then live. You
                  are never billed twice: anything up to your cursor that comes
                  back is flagged `"replay": true` and free (on a watchlist,
                  this can include a few messages from the seconds around your
                  disconnection); what comes after it is billed like live
                  messages, even when it carries `"replay": true`. On a
                  watchlist, a wallet removed (or the list cleared) while you
                  were away may not be replayed. Beyond the window, a
                  `REPLAY_TOO_OLD` notice gives `details.restFromMs` (once for a
                  whole watchlist): read the current balances again over REST.
                  Not available on a `wallets` list.
                required: false
        headers: []
        jsonPayloadSchema:
          type: object
          properties:
            op:
              type: string
              const: subscribe
              x-parser-schema-id: <anonymous-schema-171>
            channel:
              type: string
              const: wallet-balances
              x-parser-schema-id: <anonymous-schema-172>
            id:
              type: string
              description: >-
                Client-chosen subscription id, echoed on every frame of this
                subscription.
              x-parser-schema-id: <anonymous-schema-173>
            params:
              type: object
              properties:
                chain:
                  type: string
                  description: >-
                    Public chain id, `evm:<id>` or `solana`. Give `address` with
                    `chain` or `chains`, or give `wallets`, or give `watchlist`.
                  x-parser-schema-id: <anonymous-schema-175>
                chains:
                  type: array
                  minItems: 1
                  items:
                    type: string
                    x-parser-schema-id: <anonymous-schema-177>
                  description: >-
                    Several chains of the wallet in one subscription, in place
                    of `chain`: public chain ids (a comma-separated string is
                    accepted too). `evm` stands for every EVM chain and combines
                    with explicit ids; no limit on the number of chains. Every
                    chain must belong to the wallet's family (EVM chains for a
                    hex address, `solana` for a base58 address). One stream and
                    one cursor for all of them; counts as one subscription. Send
                    `chain` or `chains`, not both.
                  x-parser-schema-id: <anonymous-schema-176>
                address:
                  type: string
                  description: The wallet address. Required with `chain` or `chains`.
                  x-parser-schema-id: <anonymous-schema-178>
                wallets:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    type: object
                    properties:
                      chain:
                        type: string
                        x-parser-schema-id: <anonymous-schema-181>
                      address:
                        type: string
                        x-parser-schema-id: <anonymous-schema-182>
                    required:
                      - chain
                      - address
                    x-parser-schema-id: <anonymous-schema-180>
                  description: >-
                    A list of 1 to 100 wallets in place of `chain` and
                    `address`; each entry takes one chain and counts as one
                    subscription, each balance carries its `wallet`. `since` is
                    not available on a list.
                  x-parser-schema-id: <anonymous-schema-179>
                watchlist:
                  type: string
                  description: >-
                    The id of one of your watchlists (`/v1/wallet/watchlist`),
                    in place of `chain`, `chains`, `address` and `wallets`:
                    every wallet of the list is followed, and the subscription
                    counts as one whatever the size of the list. Wallets added
                    or removed over REST are followed or dropped within seconds,
                    without subscribing again. The ack carries `watchlist`
                    (`id`, `version`, `wallets`). When the watchlist is deleted
                    or purged, the subscription receives `NOT_FOUND` and ends.
                    On a watchlist, a `RATE_LIMITED` notice with
                    `details.refused` says how many of its wallets cannot be
                    followed for now; the others keep coming.
                  x-parser-schema-id: <anonymous-schema-183>
                updatePeriod:
                  type: integer
                  minimum: 0
                  maximum: 60000
                  default: 0
                  description: >-
                    Milliseconds, 0 to 60000, default 0: every transaction as it
                    lands, in its own message (snapped up to 0, 100, 200, 250,
                    500, 1000, 2000, 5000, 10000, 30000, 60000; the ack carries
                    the value applied). Above 0, one message per period carries
                    the latest balance (the greatest `block`, `logIndex`) of
                    each wallet, chain and token that changed in the period; a
                    period that piles up more than 256 balances, or 256 KB of
                    them, is sent at once and the next one starts, no balance
                    left out. `"block"` is not available on this channel.
                  x-parser-schema-id: <anonymous-schema-184>
                excludeSpam:
                  type: boolean
                  default: false
                  description: >-
                    `true` leaves out the balances of tokens flagged as spam; a
                    token without a spam verdict is delivered. On a list, once,
                    next to `wallets`.
                  x-parser-schema-id: <anonymous-schema-185>
              x-parser-schema-id: <anonymous-schema-174>
            since:
              type: string
              description: >-
                Optional, next to `params`, one wallet (on one chain or several)
                or a watchlist: the `cursor` of the last message you received.
                You get every balance change after it (up to 5 minutes back,
                flagged `"replay": true`: keep the greatest (`block`,
                `logIndex`) and they change nothing), then live. You are never
                billed twice: anything up to your cursor that comes back is
                flagged `"replay": true` and free (on a watchlist, this can
                include a few messages from the seconds around your
                disconnection); what comes after it is billed like live
                messages, even when it carries `"replay": true`. On a watchlist,
                a wallet removed (or the list cleared) while you were away may
                not be replayed. Beyond the window, a `REPLAY_TOO_OLD` notice
                gives `details.restFromMs` (once for a whole watchlist): read
                the current balances again over REST. Not available on a
                `wallets` list.
              x-parser-schema-id: <anonymous-schema-186>
          required:
            - op
            - channel
            - id
            - params
          x-parser-schema-id: <anonymous-schema-170>
        title: Subscribe
        description: Client frame opening the subscription (additive, ack is explicit).
        example: No examples found
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: subscribe
          - id: x-parser-message-name
            value: subscribe
    bindings: []
    extensions: &ref_0
      - id: x-parser-unique-object-id
        value: wallet-balances
  - &ref_1
    id: receive-wallet-balances
    title: Wallet Balances Stream frames
    type: receive
    messages:
      - &ref_3
        id: ack
        payload:
          - name: Ack
            description: 'Server acknowledgement: the subscription is live.'
            type: object
            properties:
              - name: type
                type: string
                description: object
                required: false
        headers: []
        jsonPayloadSchema:
          type: object
          x-parser-schema-id: <anonymous-schema-187>
        title: Ack
        description: 'Server acknowledgement: the subscription is live.'
        example: |-
          {
            "op": "subscribed",
            "id": "holders-tab",
            "channel": "wallet-balances",
            "updatePeriod": 0,
            "watchlist": {
              "id": "app-holders",
              "version": 4183,
              "wallets": 48210
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: ack
          - id: x-parser-message-name
            value: ack
      - &ref_4
        id: balance
        payload:
          - name: Balances
            description: >-
              Server push frame, one per transaction and followed wallet, `data`
              always an array of its token balances (a batch per period with
              `updatePeriod`): 1 credit per wallet and chain in the message (one
              transaction: 1, however many tokens it moved).
            type: object
            properties:
              - name: type
                type: string
                description: object
                required: false
              - name: description
                type: string
                description: >-
                  `data` is an array of balances `{wallet, chain, token,
                  rawBalance, decimals, balance, block, logIndex, txHash,
                  publishedAt}`: the balance of each token the transaction moved
                  for the wallet, after the transaction. `rawBalance` is an
                  exact integer string in the token's smallest unit, always
                  present; `decimals` is an integer or `null` when not known
                  yet; `balance` is `rawBalance` scaled by `decimals`, an exact
                  decimal string (the format of `amount` on
                  `/v1/wallet/positions`), `null` when `decimals` is `null`.
                  `logIndex` orders changes within a block: compare it, never
                  read meaning into it. `publishedAt` is when the balance was
                  published on our side (ms) or `null`, not the block time.
                  `cursor` resumes a single-wallet or watchlist subscription;
                  `"replay": true` flags a message you may already have.
                required: false
        headers: []
        jsonPayloadSchema:
          type: object
          description: >-
            `data` is an array of balances `{wallet, chain, token, rawBalance,
            decimals, balance, block, logIndex, txHash, publishedAt}`: the
            balance of each token the transaction moved for the wallet, after
            the transaction. `rawBalance` is an exact integer string in the
            token's smallest unit, always present; `decimals` is an integer or
            `null` when not known yet; `balance` is `rawBalance` scaled by
            `decimals`, an exact decimal string (the format of `amount` on
            `/v1/wallet/positions`), `null` when `decimals` is `null`.
            `logIndex` orders changes within a block: compare it, never read
            meaning into it. `publishedAt` is when the balance was published on
            our side (ms) or `null`, not the block time. `cursor` resumes a
            single-wallet or watchlist subscription; `"replay": true` flags a
            message you may already have.
          x-parser-schema-id: <anonymous-schema-188>
        title: Balances
        description: >-
          Server push frame, one per transaction and followed wallet, `data`
          always an array of its token balances (a batch per period with
          `updatePeriod`): 1 credit per wallet and chain in the message (one
          transaction: 1, however many tokens it moved).
        example: |-
          {
            "op": "event",
            "id": "holders-tab",
            "channel": "wallet-balances",
            "data": [
              {
                "wallet": "DfMxre4cKmvogbLrPigxmibVTTQDuzjdXojWzjCXXhzj",
                "chain": "solana",
                "token": "CBZq5ycLcr6mnYvjFTPuYSuhgS3ujsiTrT4sqatBpump",
                "rawBalance": "15915963200000",
                "decimals": 6,
                "balance": "15915963.2",
                "block": 371204455,
                "logIndex": 81592322,
                "txHash": "5hG8mJ3tX1qYw2Zk9uVb7nRc4pLs6dEa8fTy1oWq3xNv2KjH9gBm5rCz7eUi4sPa6tDl8yFo1wXn3vQk5jMh",
                "publishedAt": 1790539767391
              }
            ],
            "asOf": 1790539767412,
            "cursor": "v2.muk95908.muk95aov"
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: balance
          - id: x-parser-message-name
            value: balance
    bindings: []
    extensions: *ref_0
sendOperations:
  - *ref_1
receiveOperations:
  - *ref_2
sendMessages:
  - *ref_3
  - *ref_4
receiveMessages:
  - *ref_5
extensions:
  - id: x-parser-unique-object-id
    value: wallet-balances
securitySchemes: []

````

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