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

# Filtering streams

> How spot.tokens and spot.trades filters combine keys, lists and ranges, and what they cost.

[`spot.tokens`](/reference/streams/spot-tokens) and [`spot.trades`](/reference/streams/spot-trades) take the same filter language. Each channel page lists its keys. This page holds the rules both share.

## How keys combine

* `{}` keeps everything: every token, or every trade, on every chain. Each key you add narrows the set.
* An item must pass every key.
* In a list, one matching value is enough.
* For an OR across keys, open a second subscription.
* `exclude` drops an item that matches any of its values, even when every other key keeps it.

```jsonc theme={null}
// A spot.tokens filter: Solana or Base tokens, launched on pump.fun or Clanker, with no mayhem mode.
{
  "chains": ["solana", "base"],
  "protocols": ["pumpfun", "clanker"],
  "exclude": { "annotations": ["mayhem_mode"] }
}
```

## Ranges

A range is `{ "min": …, "max": … }`. Both ends are inclusive, and either end can be left out.

* Money and percentages are [decimal strings](/concepts/reading-responses#decimals), such as `"100000"`. Stream keys end in `Pct`.
* Counts, basis points and milliseconds are integers, such as `3600000`.
* A percentage uses the 0–100 scale the payload uses.
* Every `…Usd` key has a `…Native` twin, in the chain's gas asset.
* A `min` above `max` is refused.

**An unknown value fails a range.** A price, market cap, liquidity, supply or holder count of zero has not been measured yet, so a zero there fails every range. A filter of `{ "max": "5000000" }` does not keep a token with no market cap.

## Names and addresses

* An EVM address matches in any letter case. A Solana address matches exactly.
* A launchpad, DEX or platform name matches in any letter case. An unknown name is accepted and matches nothing, so a misspelled venue fails silently.
* An unknown chain, flag, stage, anchor, annotation, social or funding kind is refused.
* A top-level `tokens`, `wallets` or `pools` address must belong to a chain that `chains` keeps. An absent `chains` keeps every chain, so one EVM address follows every EVM chain.
* A list holds at most 100 values. `tokens` on `spot.tokens` takes 1 to 100. `tokens`, `wallets` and `pools` on `spot.trades` have no cap of their own; the address budget bounds them.

## The address budget

One API key holds 20 subscriptions across all its connections. Those subscriptions share one budget of 2,000 addresses.

| Subscription | Cost |
| - | - |
| A `spot.tokens` or `spot.trades` filter that names addresses | One per address in its top-level `tokens`, `wallets` or `pools` lists. An address named twice in one list counts once. An address in two lists counts twice. |
| A `spot.tokens` or `spot.trades` filter that names no address | One |
| `spot.candles` | One |
| `wallet.balances` or `spot.positions` | One per wallet |

Other address keys cost nothing: `devAddresses`, `fundingAddresses`, every `exclude` list, and the lists inside a trade filter's `token` key.

Each subscription pays for its own addresses, so two subscriptions that name one address spend two units.

A subscribe over either cap gets a `VALIDATION_ERROR`. Its message names the cap that ran out. When closing subscriptions would free room, it also says how much the key holds.

## Errors

A refused filter gets an `error` frame, and the connection stays open.

| Code | When |
| - | - |
| `UNSUPPORTED_CHAIN` | A chain is not [supported](/concepts/chains) |
| `VALIDATION_ERROR` | An unknown key, a value of the wrong type or set, a range with `min` above `max`, a list over its cap, an address of the wrong format, or a spent cap |

The error's `details[].field` is the key's path, such as `stats.5m.buys`, `exclude.wallets` or `flags[0]`. A refusal from the subscription cap names `channel`, and one from the address budget names `filters`.

```json theme={null}
{
  "type": "error",
  "id": "screener",
  "code": "VALIDATION_ERROR",
  "message": "One or more parameters are invalid.",
  "details": [{ "field": "stats.5m.buyz", "message": "No filter key is named `buyz`." }]
}
```


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