> ## 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.

# Watchlists

> Keep a list of wallets on our side, change it by adding and removing wallets, and cite it by id: on REST to filter the holders, top traders and trades of a token, and on the trades, wallet-trades and wallet-balances streams. Built for apps that follow thousands of wallets.

A watchlist is a list of wallets kept on our side. You build it once, change it by adding and removing wallets, and cite it by its id instead of sending every wallet again: one list for the holders tab of your own users, however many wallets it follows. Read the holders, top traders and trades of a token among its wallets over REST ([filter market endpoints](#filter-market-endpoints-by-a-watchlist)), and follow their balances and trades live on one stream subscription, or the trades of a token made by them. Managing watchlists is free.

## A watchlist

* **Its id**: yours (1 to 64 characters among `A-Z a-z 0-9 _ . : -`, not starting with a dot), or one we generate when you create it without one (`wl_` + 16 hex characters). Ids are private to your account: another account can use the same id for its own list.
* **Its wallets**: each wallet is `{ "address": "…", "chain": "…" }` (one chain, `solana` or `evm:<id>`) or `{ "address": "…", "chains": "evm" }` (the wallet on every EVM chain, counted as one wallet). An address is either on every EVM chain or on the EVM chains you name, never both: adding `{ "address": "0xabc…", "chains": "evm" }` to a list that has `0xabc…` on Base (or the reverse) comes back in `rejected` (`INVALID_PARAM`), and the other wallets are applied. The same address on several named chains is one wallet per chain. EVM addresses are lowercased, Solana addresses kept as they are. The rules are those of the `wallet` and `chains` parameters of the wallet streams.
* **Its version**: a number that moves each time its wallets change, and never goes back, even after a deletion or a purge.

## Changing it

* [Create](https://docs.serialized.xyz/endpoints/watchlist-create.md), optionally with its first wallets. Creating an id you already have adds the wallets to it.
* [Add](https://docs.serialized.xyz/endpoints/watchlist-add.md) and [remove](https://docs.serialized.xyz/endpoints/watchlist-remove.md) up to 10,000 wallets per call. Both are idempotent: sending the same call twice changes nothing the second time (`alreadyIn`, `notIn`), and the `version` only moves when something changed. A list is never replaced as a whole.
* An invalid wallet does not fail the call: it comes back in `rejected` with its index and the error, and the other wallets are applied.
* [Clear](https://docs.serialized.xyz/endpoints/watchlist-clear.md) removes every wallet at once and keeps the list and its stream subscriptions. [Delete](https://docs.serialized.xyz/endpoints/watchlist-delete.md) removes the list; its id is free again at once, and its stream subscriptions end.
* Read your [lists](https://docs.serialized.xyz/endpoints/watchlist-list.md), [one list](https://docs.serialized.xyz/endpoints/watchlist-get.md) and its [wallets](https://docs.serialized.xyz/endpoints/watchlist-wallets.md), page by page.

## Limits

| | Per account |
| - | - |
| Wallets, across all your watchlists | 1,000 (contact us for more) |
| Watchlists | 1,000 |
| Wallets per add or remove call | 10,000 |

A call that would go past a limit is refused whole, nothing is written: `429` `RATE_LIMITED` with `details.limit` (`watchlistWallets` or `watchlists`), `details.max` and `details.current`. Remove wallets or delete a list, then send the call again.

## Filter market endpoints by a watchlist

Pass `watchlist=<id>` to keep only the wallets of one of your watchlists:

| Endpoint | With `watchlist` |
| - | - |
| [Token holders](https://docs.serialized.xyz/endpoints/token-holders.md) | The wallets of the list that hold the token, largest balance first, searched among all its holders (small balances included), each with its token holders row (`amount`, value, PnL, labels, and its rank among all holders when the token has no more holders than the list has wallets on the chain, up to 50,000): the snapshot behind a holders tab. Any list size; pages of up to 100, `offset` can go past 5,000. |
| [Token top traders](https://docs.serialized.xyz/endpoints/token-top-traders.md), [pool top traders](https://docs.serialized.xyz/endpoints/pool-top-traders.md) | The same ranking (`timeframe`, `sortBy`, `order`, `limit`) among the list's wallets. `rank` is the position among them; `meta.traderCount` is the number of them that traded the token (or in the window). Any list size; above 2,000 wallets on the chain, a windowed ranking takes a window of at most 50,000 traders. |
| [Token trades](https://docs.serialized.xyz/endpoints/token-trades.md) (GET and POST), [pool trades](https://docs.serialized.xyz/endpoints/pool-trades.md) | Only the trades of the list's wallets, with every other filter. Not together with `makers` or `maker`. Any list size; above 2,000 wallets on the chain, each call searches up to 2,000 trades of the feed, so a page can be short, or empty, with `meta.hasMore: true`: follow `meta.nextCursor`. |

* The wallets that count are those of the requested chain: on an EVM chain, the wallets on that chain and those added with `chains: "evm"`.
* Every endpoint takes a list of any size. Up to 2,000 wallets on the chain, top traders and trades filter exactly like `makers`; above, trades report what each call searched in `meta.watchlist.scanned` (`trades`, `from`, `to`).
* `meta.watchlist` gives the list's `id`, the `version` applied and its `wallets` at that version. A change to the list shows on the next call (on token holders, within a few seconds; on top traders with more than 2,000 wallets on the chain, within 15 seconds, and `meta.watchlist.version` says which version the ranking reflects).
* The credits are those of the endpoint, as without the filter, and the call counts as use of the list.

## Unused watchlists

A watchlist that is not used for 48 hours is purged: any call on it counts as use, and so does a stream subscription that follows it, for as long as it stays open. For 30 days its id then answers `404` `NOT_FOUND` with `details.reason: "purged"` and `details.purgedAt`; create it again with the same id. An id you never created, or deleted, answers `404` with `details.reason: "unknown"`.

## Follow it live

Subscribe to a watchlist on the [Wallet Balances Stream](https://docs.serialized.xyz/streams/wallet-balances-stream.md) (the exact token balances of its wallets, one message per transaction and wallet while your connection keeps up) or the [Wallet Trades Stream](https://docs.serialized.xyz/streams/wallet-trades-stream.md) (every trade of its wallets) with `"params": {"watchlist": "<id>"}`:

* **One subscription**, whatever the number of wallets: on these two channels it counts as one in the stream limits of your account.
* **Changes apply live.** Wallets you add or remove are followed or dropped within seconds, without subscribing again.
* **The end of the list ends the subscription.** When the watchlist is deleted or purged, the subscription receives `NOT_FOUND` (`details.reason`) and ends.
* **Billing** is the channel's own: 1 credit per wallet and chain in each message. A wallet that does not move costs nothing.
* **A typical holders tab**: keep your users' wallets in one watchlist; subscribe on `wallet-balances` with that watchlist and wait for the ack, keep the messages that arrive, read the page with [token holders](https://docs.serialized.xyz/endpoints/token-holders.md) and `watchlist=<id>`, then apply the kept messages for that token on top of it, and the next ones as they come. Nothing is sent before the ack, and a holders page can take a few seconds to show a change: reading it after the ack leaves no gap.

On the [Trades Stream](https://docs.serialized.xyz/streams/trades-stream.md#following-a-watchlist), add `"watchlist": "<id>"` to the `params` of a token or a market: only the trades of the list's wallets on that token are pushed and billed, the live twin of [token trades](https://docs.serialized.xyz/endpoints/token-trades.md) with `watchlist`. It counts as one subscription whatever the size of the list, and changes apply live too.

On the [Wallet Positions Stream](https://docs.serialized.xyz/streams/wallet-positions-stream.md#following-a-watchlist) and the [Wallet Portfolio Stream](https://docs.serialized.xyz/streams/wallet-portfolio-stream.md#following-a-watchlist), the same `"params": {"watchlist": "<id>"}` follows every wallet of the list as its own view: a `snapshot` per wallet, then its deltas, each message with its `wallet`. There each wallet counts as one subscription in your limits (a list that does not fit is refused whole), changes apply live too, and billing is that of a subscription to each wallet.

## Credits

Creating, changing, reading, clearing and deleting watchlists costs 0 credits, and these calls stay open when your credits run out: you can always remove wallets. They have their own rate group, Watchlist: 120 calls per minute per key by default, raised on request, each call counting one whatever the number of wallets it carries. It is never limited by the Wallet group, nor by filtered token holders pages; your per-minute limit and burst cap apply as to every call ([rate limits](https://docs.serialized.xyz/authentication.md#rate-limits)). A market endpoint with `watchlist` costs what it costs without it: 2 credits per call for token holders, like any token holders page. Token holders with `watchlist` has its own rate group too, Watchlist holders: 120 calls per minute per key by default, raised on request, each call counting one whatever its page size; the `X-RateLimit-Group-*` headers of every response show what is left.


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