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

# Rate limits and best practices

> DexPaprika API rate limits, pagination rules, caching strategies, and performance optimization tips for building efficient applications.

## Rate limits

| Tier | Credit allowance | Requests per minute | Notes |
| - | - | - | - |
| **Free (no key)** | 10,000 per IP, rolling 30 days | 15 / min | No API key needed to start |
| **Free (registered key)** | 100,000, rolling 30 days | 30 / min | [Free API key](https://console.dexpaprika.com), no card |
| **Dev** | 500,000 per billing month | 120 / min | $30 a month. $20 per additional 1M. Served from [api-pro.dexpaprika.com](https://docs.dexpaprika.com/api-pro/introduction.md), with a key |
| **Pro** | 5,000,000 per billing month | 500 / min | \$20 per additional 1M. Served from [api-pro.dexpaprika.com](https://docs.dexpaprika.com/api-pro/introduction.md), with a key |
| **Enterprise** | Agreed per contract | Agreed per contract | Streaming unmetered |

Free tiers, keyed or keyless, call `api.dexpaprika.com`. Dev, Pro and Enterprise call `api-pro.dexpaprika.com` and must send the key in the `Authorization` header; [upgrading to Pro](https://docs.dexpaprika.com/api-pro/upgrading.md) is the whole change.

When you exceed the per-minute rate, requests return HTTP 429; retry after a short pause. When the credit allowance runs out, requests return HTTP 402, and retrying will not help.

### How the allowance refills

The tiers refill differently, and the difference changes how you pace heavy work.

**Free tiers use a rolling 30-day window.** What counts is your usage over the last 30 days, and the window advances an hour at a time. There is no first-of-the-month reset to wait for: credits come back 30 days after you spent them, to the hour. A burst today therefore constrains you for the next 30 days rather than until the calendar turns over. With a key, `period_started_at` on `GET /usage` shows where your window currently begins.

**Pro and Enterprise reset on the billing period**, anchored to the subscription date, so the whole allowance returns at once.

The practical difference is backfills. Under a calendar month you could spend the allowance and wait for the 1st. Under a rolling window a large one-off pull keeps its weight for a full 30 days, so either spread heavy historical work across days or size it against Pro.

### Requests and credits

An HTTP call is a **request**. What it spends is a **credit**. One request costs one credit, with no compute units and no per-endpoint weights: a light call and a heavy call cost the same. Credits are the customer-facing unit, and they are what [console.dexpaprika.com](https://console.dexpaprika.com), invoices and the [pricing page](https://dexpaprika.com/api/pricing) count.

Two places the distinction matters. The per-minute limit counts requests, so 15 per minute means 15 HTTP calls per minute. Batch endpoints charge one credit per item, so one HTTP call for 10 tokens is 1 request and 10 credits.

> [!NOTE]
>
> Need more headroom? [Pro](https://docs.dexpaprika.com/api-pro/introduction.md) raises the monthly allowance to 5M credits with per-1M overage, and Enterprise is custom. Plans and checkout are on [pricing](https://dexpaprika.com/api/pricing).

## OHLCV limits by plan

The pool OHLCV endpoint (`GET /networks/{network}/pools/{pool_address}/ohlcv`) caps how far back you can query and how fine the candles can be. The cap depends on your plan:

| Plan | Candle intervals | History depth |
| - | - | - |
| **Free (no key)** | `1h`, `6h`, `12h`, `24h` | last 24 hours |
| **Free (registered key)** | `10m` and longer | last 7 days |
| **Dev** | all (`1m` to `24h`) | last 30 days |
| **Pro** | all | unlimited |
| **Enterprise** | all | unlimited |

How the history cap is applied:

* `start` is required and must fall inside the window; `start=-24h` selects the last 24 hours, which every plan may query. `end`, when given, must fall inside it too.
* `count_back` counts candles back from `end`, so `count_back` × `interval` must fit inside the window as well.
* If `start` is inside the window but the range reaches before it, the request succeeds and the start is moved up to the edge of the window. You get a `403` only when the whole range lies before the window.

A request outside the plan's limits returns **HTTP 403** with the `plan_required` envelope. `param` names the parameter that broke the limit, `required_tier` the lowest plan that lifts it, and `message` says the same in words. A free key asking for a month of history:

```json theme={null}
{
  "error": "plan_required",
  "tier": "free",
  "required_tier": "dev",
  "param": "start",
  "message": "OHLCV history beyond the last 7 days requires a Dev plan (30 days) or a Pro plan (unlimited)",
  "links": {"pricing": "https://dexpaprika.com/api/pricing", "docs": "https://docs.dexpaprika.com/", "coupon": "https://dexpaprika.com/api/pricing?coupon=START10"}
}
```

A keyless request for `interval=1m`:

```json theme={null}
{
  "error": "plan_required",
  "tier": "keyless",
  "required_tier": "free",
  "param": "interval",
  "message": "OHLCV intervals below 1h require an API key (free key: 10m and up, Dev and Pro plans: all intervals)",
  "links": {"register": "https://console.dexpaprika.com", "pricing": "https://dexpaprika.com/api/pricing", "docs": "https://docs.dexpaprika.com/", "coupon": "https://dexpaprika.com/api/pricing?coupon=START10"}
}
```

[Token OHLCV](https://docs.dexpaprika.com/api-reference/tokens/get-ohlcv-data-for-a-token.md) (`GET /networks/{network}/tokens/{token_address}/ohlcv`) needs a paid plan. Keyless requests and free keys get `403` with `"error": "plan_required"` and no `param`, because the whole endpoint is gated (see [paid-only endpoints](#paid-only-endpoints)); Dev and above follow the Dev, Pro and Enterprise rows of the table above.

[Pool indicators](https://docs.dexpaprika.com/api-reference/pools/get-a-technical-indicator-for-a-pool.md) (`GET /networks/{network}/pools/{pool_address}/indicators`) are computed from pool OHLCV candles and follow the same table, for all five indicators, with the same `403` bodies. Without `interval`, a keyless request defaults to `1h` rather than `24h`, since a daily candle does not fit its 24-hour window. [Token indicators](https://docs.dexpaprika.com/api-reference/tokens/get-a-technical-indicator-for-a-token.md) need a paid plan, like token OHLCV.

The interval check runs first: a free key asking for `interval=1m` over a month gets the interval message, not the history one. A `403` is not retryable; fix the parameters or upgrade the plan.

***

## Paid-only endpoints

A few endpoints are not available to keyless callers or free keys at all. They need a Dev, Pro or Enterprise key, on the paid hosts (`api-pro.dexpaprika.com` for REST, `streaming-pro.dexpaprika.com` for SSE):

| Endpoint | Free (no key) | Free (registered key) | Dev / Pro / Enterprise |
| - | - | - | - |
| `GET /networks/{network}/pools/{pool_address}/transactions` | `403` | `403` | full access |
| `GET /sse/transactions` and `POST /sse/transactions` | `403` | `403` | full access |
| `GET /networks/{network}/tokens/{token_address}/ohlcv` ([token OHLCV](https://docs.dexpaprika.com/api-reference/tokens/get-ohlcv-data-for-a-token.md)) | `403` | `403` | full access, within the Dev / Pro history window |
| `GET /networks/{network}/tokens/{token_address}/indicators` ([token indicators](https://docs.dexpaprika.com/api-reference/tokens/get-a-technical-indicator-for-a-token.md)) | `403` | `403` | full access, within the Dev / Pro history window |
| `GET /sse/ohlcv` | `403` | `403` | full access |

The refusal is the `plan_required` envelope without a `param`, returned before any data is read, so it costs no credits. `tier` is `keyless` or `free`; `required_tier` is `dev`:

```json theme={null}
{
  "error": "plan_required",
  "tier": "keyless",
  "required_tier": "dev",
  "message": "this endpoint requires a Dev or Pro plan",
  "links": {
    "register": "https://console.dexpaprika.com",
    "pricing": "https://dexpaprika.com/api/pricing",
    "docs": "https://docs.dexpaprika.com/",
    "coupon": "https://dexpaprika.com/api/pricing?coupon=START10"
  }
}
```

Details of every field are in [error handling](https://docs.dexpaprika.com/knowledge-base/error-handling.md#403-forbidden-paid-only-endpoint).

Every other REST endpoint answers on the free tier (subject to the credit and per-minute limits above), `/sse/reserves` opens with a free key, and `/sse/prices` streams keyless on the [showcase assets](https://docs.dexpaprika.com/streaming/showcase-streams.md) and on any token with a key.

***

## Pagination rules

The search endpoints page with a cursor. `GET /networks/{network}/dexes` and `GET /networks/{network}/pools/{pool_address}/transactions` are the two that still page with numbers.

| Rule | Value |
| - | - |
| **Cursor endpoints** | All `*/search` paths: read `has_next_page`, send `next_cursor` back as `cursor` |
| **First page** | `page=1` (1-indexed), on the two page-based endpoints only |
| **Page 0 behavior** | Silently treated as page 1 |
| **Max items per page** | 100 (via `limit` parameter) |
| **Default items per page** | Varies by endpoint (typically 10 or 50) |
| **Transaction pages** | Max 100 pages; use `cursor` for deeper history |

***

## Reduce API calls

### Use batch pricing

Instead of making one request per token:

```
GET /networks/ethereum/tokens/0xc02a.../  → 1 request, 1 credit
GET /networks/ethereum/tokens/0xa0b8.../  → 1 request, 1 credit
GET /networks/ethereum/tokens/0x6b17.../  → 1 request, 1 credit
= 3 requests, 3 credits
```

Use batch pricing for up to 10 tokens at once:

```
GET /networks/ethereum/multi/prices?tokens=0xc02a...,0xa0b8...,0x6b17...
= 1 request, billed as 3 credits (one per token)
```

Batching collapses three round-trips into one HTTP call, which cuts latency, connection overhead and pressure on the per-minute request limit. It does not cut your credit spend: each token in the batch bills as one credit, so 10 tokens cost 10 credits whether you fetch them one at a time or together. Batch for speed and for headroom against the per-minute limit, not to save credits.

### Use streaming for real-time data

> [!TIP]
>
> Sizing a workload before you pick a plan? [Plan your credit usage](https://docs.dexpaprika.com/knowledge-base/credit-usage.md) has measured update rates, four worked cost models, and the point where streaming stops costing less than polling.

If you need live prices, don't poll the REST API in a loop. Open one streaming connection instead:

```bash theme={null}
# Polling (bad): 60 requests/minute for 1 token
while true; do curl ...; sleep 1; done

# Streaming (good): 1 connection, updates pushed only when the price moves
curl -N "https://streaming.dexpaprika.com/sse/prices?method=token_price&chain=ethereum&address=0xc02a..."
```

A single POST `/sse/prices` connection accepts up to **25 assets**. Concurrent SSE streams are capped per plan: 10 keyless (counted per IP), 10 on a free key, 30 on Dev and 100 on Pro (counted per account, from any IP). The next stream over the cap returns `429` with `"error":"rate_limited"` and a message starting `Concurrent stream limit reached`; close an open stream before starting another.

Streaming is billed the same way as REST: each update delivered over the stream costs one credit. Because updates are pushed only when a swap moves the price, an idle market costs nothing, but a fast-moving one draws on your credit allowance much as polling would. Budget for the update rate of what you subscribe to, not the number of connections.

### Cache static data

Some data changes rarely and can be cached:

| Data | Cache for |
| - | - |
| Network list (`/networks`) | 24 hours |
| DEX list (`/networks/{n}/dexes`) | 1 hour |
| Token metadata (name, symbol, decimals) | 24 hours |
| Pool token pair info | 24 hours |
| OHLCV historical data (completed candles) | Forever (completed candles don't change) |

Data that changes frequently and should be fetched fresh:

* Token prices
* Pool volumes and transaction counts
* Recent transactions
* Current OHLCV candle (incomplete)

### Request only what you need

* Use `limit` to control page size. Do not fetch 100 items if you need 5
* Use `order_by` and `sort` to get the most relevant results first
* Use the filter endpoint for targeted queries instead of fetching all pools and filtering client-side

***

## Handle errors gracefully

### Implement exponential backoff

When requests fail, don't retry immediately in a tight loop:

```python theme={null}
import time
import requests

def fetch_with_backoff(url, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url)
        if response.status_code == 200:
            return response.json()
        if response.status_code == 429:
            wait = 2 ** attempt  # 1s, 2s, 4s
            time.sleep(wait)
            continue
        if response.status_code >= 500:
            wait = 2 ** attempt
            time.sleep(wait)
            continue
        # 400, 404, 410 -- don't retry, fix the request
        response.raise_for_status()
    raise Exception("Max retries exceeded")
```

### Don't retry client errors

* **400**: fix the request parameters
* **404**: verify the network ID and addresses
* **410**: use the replacement endpoint

Only retry on **429** (rate limit) and **500** (server error).

***

## Streaming best practices

### Validate before streaming

The streaming API rejects the entire request if any asset is invalid. Always verify tokens exist via REST first:

```python theme={null}
# Validate each token before streaming
for token in tokens:
    resp = requests.get(f"https://api.dexpaprika.com/networks/{token['chain']}/tokens/{token['address']}")
    if resp.status_code != 200:
        tokens.remove(token)  # Remove invalid tokens
```

### Use batched POST for multiple tokens

Instead of opening multiple GET connections:

```
# Bad: 3 connections for 3 tokens
GET /sse/prices?method=token_price&chain=ethereum&address=0xaaa...
GET /sse/prices?method=token_price&chain=ethereum&address=0xbbb...
GET /sse/prices?method=token_price&chain=ethereum&address=0xccc...
```

Use one POST connection:

```bash theme={null}
# Good: 1 connection for up to 25 tokens
POST /sse/prices
[
  {"chain": "ethereum", "address": "0xaaa...", "method": "token_price"},
  {"chain": "ethereum", "address": "0xbbb...", "method": "token_price"},
  {"chain": "ethereum", "address": "0xccc...", "method": "token_price"}
]
```

### Reconnect with backoff

Streaming connections can drop (network issues, server restarts). Always implement auto-reconnection:

```python theme={null}
import time

def stream_with_reconnect(url, payload, max_backoff=60):
    backoff = 1
    while True:
        try:
            resp = requests.post(url, json=payload, stream=True,
                headers={"Accept": "text/event-stream"})
            if resp.status_code != 200:
                raise Exception(f"HTTP {resp.status_code}")
            backoff = 1  # Reset on successful connection
            for line in resp.iter_lines():
                if line and line.startswith(b'data:'):
                    process_event(line)
        except Exception as e:
            print(f"Disconnected: {e}. Reconnecting in {backoff}s...")
            time.sleep(backoff)
            backoff = min(backoff * 2, max_backoff)
```

### Parse prices as decimals

The streaming `p` field is a string, not a number. Use decimal parsing to avoid floating-point precision issues:

```python theme={null}
from decimal import Decimal
price = Decimal(data['p'])  # Not float(data['p'])
```

***

## Production checklist

> **Before going to production**
>
> * [ ] Cache network and DEX lists
> * [ ] Use batch pricing where possible
> * [ ] Use streaming instead of polling for live prices
> * [ ] Implement exponential backoff for retries
> * [ ] Handle all HTTP status codes (200, 400, 404, 410, 429, 500)
> * [ ] Parse streaming prices as decimals, not floats
> * [ ] Validate tokens before adding to streaming connections
> * [ ] Monitor credit spend in [console.dexpaprika.com](https://console.dexpaprika.com) against your tier's allowance (streaming updates included)
> * [ ] Consider [Pro](https://docs.dexpaprika.com/api-pro/introduction.md) if approaching your allowance, and budget time for the base URL and header change it needs

### FAQs

> **Is there a per-minute rate limit?**
>
> Yes. The free tier allows 15 requests a minute without a key and 30 with a [free key](https://console.dexpaprika.com), and Pro allows 500, alongside the credit allowance. Exceeding the per-minute rate returns HTTP 429; retry after a short pause.

> **What is the difference between a request and a credit?**
>
> A request is one HTTP call. A credit is what it spends. One request costs one credit on every plan, with no compute units or per-endpoint multipliers, so the two numbers match except on batch endpoints, where one request charges one credit per item.

> **Do streaming updates count toward my credits?**
>
> Yes. Each price update delivered over an SSE stream costs one credit, the same as a REST call. Updates are pushed only when a swap moves the price, so an idle subscription costs nothing, but an active one draws on your credit allowance.

> **Can I increase the free tier limit?**
>
> Registering for a free API key raises the keyless 10,000 credits to 100,000. Both are measured over a rolling 30 days, not a calendar month. Beyond that, [Pro](https://docs.dexpaprika.com/api-pro/introduction.md) includes 5,000,000 credits a month on the billing period, with per-1M overage.

> **Why does the OHLCV endpoint return 403?**
>
> Your plan's OHLCV window or candle size was exceeded. Without a key you get 1h+ candles over the last 24 hours; a free key gets 10m+ candles over 7 days; Dev gets every interval over 30 days; Pro and Enterprise have no cap. The 403 message says which plan lifts the limit.


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