---
name: dexpaprika-api
description: "Query on-chain DEX data and stream real-time crypto prices using DexPaprika: token prices, liquidity pools, OHLCV history, swap transactions, advanced pool filtering, and live price streaming via SSE across 36+ blockchains. Use this skill whenever the user wants to fetch crypto token prices, look up pool or DEX data, get historical candlestick data, find new pools, filter pools by volume/transactions/age, stream live prices, build real-time dashboards, or build anything that needs on-chain DEX data. Also use when the user mentions DexPaprika, dexpaprika, streaming crypto prices, or SSE price feeds. Docs: https://docs.dexpaprika.com (REST) and https://docs.dexpaprika.com/streaming/introduction (streaming)"
---

# DexPaprika API

On-chain DEX data and real-time price streaming across 36+ blockchains, 33M+ tokens, 36M+ pools. No API key needed to start: keyless requests get 50,000 credits a month at 30 requests a minute, a free key raises that to 300,000, and Pro includes 5,000,000 at 300 a minute (see the limits at the end of this file).

| Service | Base URL | Purpose |
|---|---|---|
| REST API | `https://api.dexpaprika.com` | Token data, pools, OHLCV, transactions, search |
| Streaming API | `https://streaming.dexpaprika.com` | Real-time price + pool-reserve updates via SSE (`/sse/prices`, `/sse/reserves`). Prices pushed when a swap moves them; reserves pushed per block in which they changed. [Full docs](https://docs.dexpaprika.com/streaming/introduction) |
| CLI | `curl -sSL .../install.sh \| sh` | Terminal tool wrapping the full API. Install: `curl -sSL https://raw.githubusercontent.com/coinpaprika/dexpaprika-cli/main/install.sh \| sh` |

All examples use curl, but any HTTP client works. The CLI (`dexpaprika-cli`) wraps every endpoint into simple commands with `--output json --raw` for scripting. REST responses are JSON. Streaming responses are Server-Sent Events.

---

## Core concepts

**Network IDs** are lowercase chain identifiers: `ethereum`, `solana`, `bsc`, `arbitrum`, `base`, `polygon`, `optimism`, `avalanche`, etc. Get the full list from `GET /networks`.

**Token addresses** are the on-chain contract addresses (e.g., `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` for WETH on Ethereum, `So11111111111111111111111111111111111111112` for SOL on Solana).

**Pool addresses** are the on-chain liquidity pool contract addresses. Find them via `GET /networks/{network}/pools/search`, optionally with a `token_address` filter.

If you don't know the network or address for a token, use search first.

---

## Endpoints

### Search (start here when you don't have addresses)

```
GET /search?query={query}
```

Search tokens, pools, and DEXes by name, symbol, or address. Case-insensitive. Use this to resolve "what's the ETH price" into the actual network + address you need.

**Example:** Find Jupiter token
```bash
curl "https://api.dexpaprika.com/search?query=jupiter"
```

---

### Token price and details

```
GET /networks/{network}/tokens/{token_address}
```

Returns name, symbol, chain, decimals, USD price, fully diluted valuation, liquidity, and volume/transaction stats at multiple time windows (24h, 6h, 1h, 30m, 15m, 5m).

**The price is at** `response.summary.price_usd`

**Example:** Get SOL price
```bash
curl "https://api.dexpaprika.com/networks/solana/tokens/So11111111111111111111111111111111111111112"
```

Extract just the price:
```bash
curl -s "https://api.dexpaprika.com/networks/solana/tokens/So11111111111111111111111111111111111111112" | jq '.summary.price_usd'
```

---

### Batch token prices

```
GET /networks/{network}/multi/prices?tokens={addr1},{addr2},{addr3}
```

Fetch USD prices for multiple tokens in one request. Comma-separated addresses, max 10 per request. Unknown or unpriced tokens are silently omitted from the response.

**Example:** WETH + USDC on Ethereum
```bash
curl "https://api.dexpaprika.com/networks/ethereum/multi/prices?tokens=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2,0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
```

Response is an array of `{id, chain, price_usd}` objects. Order is not guaranteed.

---

### Pools on a network (ranking and filtering)

```
GET /networks/{network}/pools/search?limit={10}&order_by={volume_usd_24h}&sort={desc}
```

One endpoint covers both "top pools" and "pools matching thresholds". The older `/networks/{network}/pools`, `/networks/{network}/pools/filter` and `/pools` all return **HTTP 410** now; this replaced them.

**Sorting and pagination:**

| Parameter | Type | Description |
|---|---|---|
| `order_by` | string | `volume_usd_24h` (default), `volume_usd_7d`, `volume_usd_30d`, `liquidity_usd`, `txns_24h`, `created_at`, `price_usd`, `price_change_percentage_24h`, `price_change_percentage_6h`, `price_change_percentage_1h`, `price_change_percentage_5m`. Anything else returns 400 with the valid list in the message |
| `sort` | string | `asc` or `desc` (default `desc`) |
| `limit` | integer | Items per page, 1-100 |
| `cursor` | string | Pass `next_cursor` from the previous response to page forward |

**Filters** (all combine with AND):

| Parameter | Type | Description |
|---|---|---|
| `volume_usd_24h_min` / `_max` | number | 24h volume in USD |
| `volume_usd_7d_min` / `_max` | number | 7d volume in USD |
| `liquidity_usd_min` / `_max` | number | Pool liquidity in USD |
| `txns_24h_min` | integer | Minimum transactions in 24h |
| `price_change_percentage_24h_min` / `_max` | number | 24h price change, percent |
| `price_change_percentage_6h_min` / `_max` | number | 6h price change, percent |
| `price_change_percentage_1h_min` / `_max` | number | 1h price change, percent |
| `price_change_percentage_5m_min` / `_max` | number | 5m price change, percent |
| `created_after` / `created_before` | integer | UNIX timestamp |

Percentage filters take signed numbers, so `price_change_percentage_1h_max=-20` returns pools down 20 percent or more over the last hour, and `price_change_percentage_1h_min=50` returns pools up 50 percent or more. Only the 6h, 1h and 5m windows are pool-only: `GET /networks/{network}/tokens/search` rejects those three as `order_by` values with a 400, drops them silently as `_min` / `_max` bounds, and token rows never carry them. The 24h window works on token search for both sorting and filtering.

Token search sorts on a shorter list than pool search: `volume_usd_24h`, `volume_usd_7d`, `volume_usd_30d`, `liquidity_usd`, `txns_24h`, `price_change_percentage_24h`, `created_at` and `fdv_usd`.

Those eight are the ones that return 200. The token 400 body also names `price_usd`, and sending `order_by=price_usd` then answers with another 400, so do not treat the message as a menu. Ordering tokens by raw price is not supported.

The response returns rows under `results`, with `has_next_page` and `next_cursor`. There is no `page_info` and no page numbers.

Use the REST parameter names above. `sort_by` and `sort_dir` are the MCP-layer names, and an unrecognized parameter name is silently ignored here, so `sort_by=...` leaves you with the default ordering. The same applies to the retired filter spelling: `volume_24h_min` is dropped without error, while `volume_usd_24h_min` applies.

**Example:** Top 5 Ethereum pools by volume
```bash
curl "https://api.dexpaprika.com/networks/ethereum/pools/search?limit=5&order_by=volume_usd_24h&sort=desc"
```

**Example:** High-volume Ethereum pools (>$100k daily volume)
```bash
curl "https://api.dexpaprika.com/networks/ethereum/pools/search?volume_usd_24h_min=100000&order_by=volume_usd_24h&sort=desc"
```

**Example:** Recently created Solana pools with activity
```bash
curl "https://api.dexpaprika.com/networks/solana/pools/search?created_after=1709251200&txns_24h_min=50&order_by=created_at&sort=desc"
```

---

### Pool details

```
GET /networks/{network}/pools/{pool_address}?inversed={false}
```

Returns liquidity, reserves, pricing, token pair info, and DEX metadata for a specific pool. Set `inversed=true` to flip the price ratio (token1/token0 instead of token0/token1).

---

### Pool OHLCV (historical candlesticks)

```
GET /networks/{network}/pools/{pool_address}/ohlcv?start={timestamp}&interval={24h}&limit={30}
```

Historical price candlestick data. `start` is required (ISO 8601 or UNIX timestamp). Optional `end` (max 1 year from start).

**Intervals:** `1m`, `5m`, `10m`, `15m`, `30m`, `1h`, `6h`, `12h`, `24h`
**Max data points:** 366 per request

**Example:** Last 30 days of daily candles for a pool
```bash
curl "https://api.dexpaprika.com/networks/ethereum/pools/0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640/ohlcv?start=2025-01-01&interval=24h&limit=30"
```

---

### Pool transactions

```
GET /networks/{network}/pools/{pool_address}/transactions?page={1}&limit={20}
```

Recent swaps, liquidity adds, and removes. Reverse chronological order. Pages 1-indexed, max 100 pages. For deep pagination, use `cursor` parameter (transaction ID) instead of page numbers.

Each transaction includes: token amounts (`amount_0`, `amount_1`), volumes (`volume_0`, `volume_1`), USD prices (`price_0_usd`, `price_1_usd`), token symbols, sender/recipient, and timestamps.

---

### Pools for a token

```
GET /networks/{network}/pools/search?token_address={token_address}&order_by={volume_usd_24h}&sort={desc}&limit={10}
```

Find all pools containing a specific token. The old `/networks/{network}/tokens/{token_address}/pools` returns **HTTP 410**; the token filter now lives on the pool search endpoint.

The filter is network-scoped only. The cross-network `/pools/search` silently ignores `token_address`, and an unknown token address returns an empty `results` array rather than an error.

Two capabilities did not survive the move and have no replacement: the `reorder` flag that made the queried token primary in the metrics, and the second-token `address` pair filter. Invert prices client side (`1/price`), and for pair queries filter `results[].tokens` yourself.

---

### DEXes on a network

```
GET /networks/{network}/dexes
```

List all DEXes on a network with their identifiers. Each row carries `dex_id` (`uniswap_v3`) and `dex_name` (`Uniswap V3`). Feed the `dex_id` into the `dex_name` filter on pool search:

```
GET /networks/{network}/pools/search?dex_name={dex_id}&order_by={volume_usd_24h}&sort={desc}&limit={10}
```

The old `/networks/{network}/dexes/{dex}/pools` returns **HTTP 410**; the DEX moved out of the path and into a query filter. The filter matches the `dex_id` case-insensitively and nothing else: pass the `dex_name` display name (`Uniswap V3`) and you get HTTP 200 with an empty `results` array, not an error.

Unlike `token_address`, `dex_name` also applies on the cross-network `/pools/search`, so `?dex_name=uniswap_v3&chains=base` works. Rows arrive under `results` with `has_next_page` and `next_cursor`, and the 24h volume field is `volume_usd_24h`. There is no `page_info` and no bare `volume_usd`; `order_by=volume_usd` is rejected with a `400`.

---

### Networks

```
GET /networks
```

Returns all supported blockchain networks with their IDs. Use these IDs in all other endpoints.

---

### Platform stats

```
GET /stats
```

High-level counts: total networks, DEXes, pools, and tokens. Useful for health checks.

---

## Streaming API: real-time prices and reserves via SSE

Stream live token prices and pool reserves over Server-Sent Events. Works with any HTTP client that supports streaming. Full docs: https://docs.dexpaprika.com/streaming/introduction

**Base URL:** `https://streaming.dexpaprika.com` (no landing page; only the `/sse/*` paths below work)

Two feeds, same transport:
- `/sse/prices`: token price updates, pushed when a swap moves the price (measured: about 1 to 52 updates a minute depending on the asset)
- `/sse/reserves`: pool reserve updates, pushed for each block in which a subscribed pool's reserves changed (USD-denominated)

The legacy `/stream` path is still accepted but **deprecated**; it now emits a `warning` event on connect and will be removed. The legacy `/reserves/stream` has been retired.

### Stream a single token (GET)

```bash
curl -N "https://streaming.dexpaprika.com/sse/prices?method=token_price&chain=ethereum&address=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
```

### Stream multiple tokens (POST), recommended for 2+ tokens

Send a JSON array of assets. Single connection, up to **25 assets**.

```bash
curl -N -X POST "https://streaming.dexpaprika.com/sse/prices" \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -d '[
    {"chain": "solana",   "address": "So11111111111111111111111111111111111111112",  "method": "token_price"},
    {"chain": "ethereum", "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",   "method": "token_price"}
  ]'
```

Each asset object requires `chain` (network ID), `address` (token contract), and `method` (`token_price`, or the deprecated `t_p` for the legacy compact shape).

### Stream pool reserves (GET, single pool)

```bash
curl -N "https://streaming.dexpaprika.com/sse/reserves?method=pool_reserves&chain=ethereum&address=0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"
```

`method=pool_reserves` follows one pool. `method=token_reserves` follows every pool containing a given token.

### SSE event formats

Default `token_price` event (full field names):

```
data: {"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","chain":"ethereum","price":"2255.59","timestamp":1778847592,"timestamp_price":1778847592,"token_price":1778847592}
event: token_price
```

`pool_reserves` event (token subscriptions emit `token_reserves` instead):

```
data: {"chain":"ethereum","pool_id":"0x88e6...","block":25100507,"tokens":[{"token_id":"0xa0b8...","reserve":"70835095690418","delta":"12018780248","price_usd":1.00,"reserve_usd":70837306.69,"delta_usd":12019.15}, ...],"total_reserve_usd":102848662.93,"total_delta_usd":8.80}
event: pool_reserves
```

Keep-alive and notice events:

```
event: ping     | data: {"time": 1778847639}            # every ~15s
event: warning  | data: {"message": "..."}              # deprecation notices, etc.
event: error    | data: {"message": "asset not found"}  # terminating error
```

| Field (`token_price`) | Meaning |
|---|---|
| `address` | Token address |
| `chain` | Chain ID |
| `price` | USD price as string (parse as decimal) |
| `timestamp` | Server send time (unix seconds) |
| `timestamp_price` | Price observation time (unix seconds) |

The legacy `t_p` method instead emits `{a, c, p, t, t_p}` short-keyed objects. Deprecated; do not use in new code.

### Python streaming example

```python
import requests, json

assets = [
    {"chain": "ethereum", "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "method": "token_price"},
    {"chain": "solana",   "address": "So11111111111111111111111111111111111111112",  "method": "token_price"}
]

r = requests.post("https://streaming.dexpaprika.com/sse/prices",
    headers={"Accept": "text/event-stream", "Content-Type": "application/json"},
    json=assets, stream=True)

# Buffer one SSE message between blank lines, then dispatch.
# Both `event:`/`data:` orderings are valid SSE and the server has emitted
# either. A line-by-line parser that assumes one order silently
# mis-dispatches, so grouping first is mandatory.
msg_lines = []
for line in r.iter_lines(decode_unicode=True):
    if line:
        msg_lines.append(line)
        continue

    event_type, data_str = "message", None
    for ml in msg_lines:
        if ml.startswith("event:"):
            event_type = ml.split(":", 1)[1].strip()
        elif ml.startswith("data:"):
            data_str = ml[5:].lstrip()
    msg_lines = []

    if event_type == "token_price" and data_str is not None:
        data = json.loads(data_str)
        print(f"{data['chain']} {data['address']}: ${data['price']}")
```

### Streaming constraints

- **Max 25 subscriptions** per POST connection. The two endpoints reject 26+ entries with different wording: `POST /sse/prices` returns `{"message":"too many assets, max 25 allowed"}`, `POST /sse/reserves` returns `{"message":"too many subscriptions"}`.
- **Max 10 concurrent SSE streams per IP.** The 11th returns `429` with `{"message":"ip stream limit exceeded"}`.
- **Ping interval:** 15 seconds. Use a missing `ping` as a connection-liveness signal.
- **All assets must be valid.** One invalid asset cancels the entire stream with HTTP 400.
- Validate assets via REST `/search` before streaming.
- Reconnect with exponential backoff on disconnect.

### Streaming errors

| Status | Meaning |
|---|---|
| 200 | Connected, streaming |
| 400 | Bad params, unsupported chain, asset not found, or one invalid asset in batch |
| 429 | IP stream limit exceeded (`{"message":"ip stream limit exceeded"}`). Retry with backoff |

Errors during an active stream arrive as SSE events: `event: error` + `data: {"message": "..."}`. Non-fatal notices (deprecations, etc.) arrive as `event: warning`. Handle HTTP errors (before stream starts), SSE errors (during), and treat unknown event names as no-ops.

---

## Constraints and limits

### REST API
- **Credit allowance:** 50,000 credits/month without a key (300,000 with a free key), at 30 requests/minute; 1 request = 1 credit, batch endpoints = 1 credit per item, each streaming update delivered = 1 credit. Pro is 5M credits/month at 300 requests/minute
- **Batch prices:** max 10 tokens per request
- **Pagination:** max 100 items per page
- **OHLCV:** max 366 data points per request, max 1 year range
- **Transactions:** max 100 pages of pagination
- **Pagination:** the search endpoints are cursor-based (`has_next_page` + `next_cursor`). Only `/networks/{network}/dexes` and `/networks/{network}/pools/{pool_address}/transactions` take `page`, 1-indexed (page=0 is silently treated as page=1)

### Streaming API
- **Max subscriptions per POST connection:** 25 (`/sse/prices`, `/sse/reserves`)
- **Concurrent SSE streams per IP:** 10 (`429 ip stream limit exceeded` on the 11th)
- **Ping interval:** 15 seconds (`event: ping`)
- **All assets must be valid** or entire stream is cancelled

---

## Error handling

| Status | Meaning | What to do |
|---|---|---|
| 200 | Success | Parse JSON response |
| 400 | Bad request (invalid params, too many tokens, bad sort field) | Check parameter values and constraints above |
| 404 | Network, token, or pool not found | Verify the network ID and address; use /search to find correct values |
| 410 | Endpoint removed | The response body names its own `replacement`. Pool and token listing/filtering moved to `/networks/{network}/pools/search` and `/networks/{network}/tokens/search` |
| 429 | Rate limit exceeded | Back off and retry; consider caching responses |
| 500 | Server error | Retry with backoff |

When a batch price request contains only invalid tokens, you get HTTP 200 with an empty array, not an error.

---

## Common workflows

### "What's the price of X?"
1. `GET /search?query=X` to find the network and token address
2. `GET /networks/{network}/tokens/{address}` to get price at `.summary.price_usd`

### "Show me the top pools on Ethereum"
1. `GET /networks/ethereum/pools/search?limit=10&order_by=volume_usd_24h&sort=desc`

### "Find new pools with high volume"
1. `GET /networks/{network}/pools/search?created_after={unix_timestamp}&volume_usd_24h_min=50000&order_by=created_at&sort=desc`

### "Get historical price data for a token"
1. Find the token's pools via `GET /networks/{network}/pools/search?token_address={address}&order_by=volume_usd_24h&sort=desc&limit=1` (the highest-volume pool is the best source)
2. `GET /networks/{network}/pools/{pool_address}/ohlcv?start={date}&interval=24h&limit=30`

### "Compare prices of multiple tokens"
1. `GET /networks/{network}/multi/prices?tokens={addr1},{addr2},{addr3}`

### "Stream live price updates for a token"
1. `GET https://streaming.dexpaprika.com/sse/prices?method=token_price&chain={network}&address={token_address}`

### "Build a real-time dashboard tracking multiple tokens"
1. Validate tokens exist via REST: `GET /search?query={name}` or `GET /networks/{network}/tokens/{address}`
2. `POST https://streaming.dexpaprika.com/sse/prices` with JSON array of `{chain, address, method: "token_price"}` objects (up to 25 per connection)
3. Parse SSE events, read price from the `price` field (a string, so parse it as a decimal for precision)

### "Monitor a token's price with alerts"
1. Stream the token via GET or POST to `streaming.dexpaprika.com/sse/prices`
2. Compare each incoming `price` value against your threshold
3. Reconnect with exponential backoff on disconnect

### "Watch a pool's liquidity in real time"
1. `GET https://streaming.dexpaprika.com/sse/reserves?method=pool_reserves&chain={network}&address={pool_address}`
2. Each `pool_reserves` event carries `block`, per-token `reserve`/`delta`, USD prices, and `total_delta_usd` (signed dollar change for the block)
3. For multi-pool/multi-token coverage, POST a JSON array (up to 25) to `/sse/reserves` mixing `pool_reserves` and `token_reserves` entries

---

## What this skill does NOT cover

- **CoinPaprika centralized exchange data.** That is a different API (`api.coinpaprika.com`)
- **Trading or swapping.** DexPaprika is read-only and does not execute trades

---

## Full documentation

- [REST API reference](https://docs.dexpaprika.com/api-reference/introduction)
- [Streaming API docs](https://docs.dexpaprika.com/streaming/introduction)
- [Tutorials](https://docs.dexpaprika.com/tutorials/tutorial_intro)
