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

# Filtering streams

> How spot.tokens, spot.trades, spot.transfers and spot.candles filters combine keys, lists and ranges, and how filters count against address limits.

[`spot.tokens`](https://docs.metastreams.io/reference/streams/spot-tokens), [`spot.trades`](https://docs.metastreams.io/reference/streams/spot-trades), [`spot.transfers`](https://docs.metastreams.io/reference/streams/spot-transfers) and [`spot.candles`](https://docs.metastreams.io/reference/streams/spot-candles) use the same filter language. This page describes the rules these channels share; each channel page lists its own keys.

## Combining filters

* `{}` matches everything: every token, trade, transfer or candle bucket, on every chain. Each key you add narrows the set.
* An item must match every key, but within a list, one matching value is enough.
* To combine keys with OR, open a second subscription.
* `exclude` removes an item that matches any of its values, even when every other key matches 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 bounds are inclusive, and you can omit either one.

* Money values and percentages are [decimal strings](https://docs.metastreams.io/concepts/reading-responses.md#decimals), such as `"100000"`. Percentage keys on streams end in `Pct`.
* Counts, basis points and milliseconds are integers, such as `3600000`.
* Percentages use the same 0–100 scale as the payload.
* Every `…Usd` key has a `…Native` counterpart, denominated in the chain's gas asset.
* A `min` greater than `max` is rejected.

**An unknown value never matches a range.** A price, market cap, liquidity, supply or holder count of zero means the value has not been measured yet, so it does not match any range. For example, a filter of `{ "max": "5000000" }` does not match a token with no market cap.

## Names and addresses

* EVM addresses are case-insensitive. Solana addresses must match exactly.
* Launchpad, DEX and platform names are case-insensitive. An unknown name is accepted but matches nothing, so a misspelled venue produces no updates and no error.
* An unknown chain, flag, stage, anchor, annotation, social or funding kind is rejected.
* Each address in a top-level `tokens`, `wallets`, `pools`, `senders` or `recipients` list must belong to a chain included in `chains`. When `chains` is omitted, every chain is included, so a single EVM address matches on every EVM chain.
* A list can contain at most 100 values, and `tokens` on `spot.tokens` takes 1 to 100. The top-level address lists on `spot.trades`, `spot.transfers` and `spot.candles` have no limit of their own; only the address limit applies.

## Address limits

Each API key can hold 20 subscriptions across all of its connections. Those subscriptions share a single limit of 2,000 addresses.

| Subscription | Cost |
| - | - |
| A `spot.tokens`, `spot.trades`, `spot.transfers` or `spot.candles` filter that includes addresses | One per address in its top-level `tokens`, `wallets`, `pools`, `senders` or `recipients` lists. An address repeated in one list counts once; an address in two lists counts twice. |
| A `spot.tokens`, `spot.trades`, `spot.transfers` or `spot.candles` filter with no addresses | One |
| `spot.holders` | One |
| `chain.nativePrices` or `spot.trending` | One |
| `wallet.balances` or `spot.positions` | One per wallet |

Other address keys do not count against the limit: `devAddresses`, `fundingAddresses`, every `exclude` list, and the lists inside a `token` key.

Each subscription counts its own addresses, so two subscriptions that name the same address use two units.

A subscribe request that exceeds either limit returns a `VALIDATION_ERROR` whose message identifies the limit. When closing subscriptions would free capacity, the message also reports the key's current usage.

## Errors

A rejected filter returns an `error` frame, and the connection stays open.

| Code | When |
| - | - |
| `UNSUPPORTED_CHAIN` | Unsupported [chain](https://docs.metastreams.io/concepts/chains.md) |
| `VALIDATION_ERROR` | An unknown key, a value of the wrong type or outside the allowed set, a range with `min` above `max`, a list over its limit, an address in the wrong format, or an exceeded subscription or address limit |

The error's `details[].field` is the path of the failing key, such as `stats.5m.buys`, `exclude.wallets` or `flags[0]`. An error from the subscription limit has the field `channel`, and an error from the address limit has the field `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.