> ## 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)**         | 30,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](/api-pro/introduction), with a key |
| **Pro**                   | 5,000,000 per billing month    | 500 / min           | \$20 per additional 1M. Served from [api-pro.dexpaprika.com](/api-pro/introduction), 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](/api-pro/upgrading) 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](/api-pro/introduction) 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).
</Note>

***

## 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](/knowledge-base/credit-usage) has measured update rates, four worked cost models, and the point where streaming stops costing less than polling.
</Tip>

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**. The free tiers hold **10 concurrent SSE streams** per IP; the 11th returns `429 ip stream limit exceeded`. Dev raises that to 30 and Pro to 100.

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

<AccordionGroup>
  <Accordion title="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](/api-pro/introduction) if approaching your allowance, and budget time for the base URL and header change it needs
  </Accordion>
</AccordionGroup>

### FAQs

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="Can I increase the free tier limit?">
    Registering for a free API key raises the keyless 30,000 credits to 100,000. Both are measured over a rolling 30 days, not a calendar month. Beyond that, [Pro](/api-pro/introduction) includes 5,000,000 credits a month on the billing period, with per-1M overage.
  </Accordion>
</AccordionGroup>

<script type="application/ld+json">
  {JSON.stringify({
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {"@type": "Question","name": "Is there a per-minute DexPaprika rate limit?","acceptedAnswer": {"@type": "Answer","text": "Yes. Free allows 15 requests a minute without a key and 30 with a free key (https://console.dexpaprika.com), and Pro 500 a minute, alongside the credit allowance. Exceeding it returns HTTP 429."}},
        {"@type": "Question","name": "What is the difference between a request and a credit?","acceptedAnswer": {"@type": "Answer","text": "A request is one HTTP call; a credit is what it spends. One request costs one credit, with no compute units. Batch endpoints charge one credit per item."}},
        {"@type": "Question","name": "Do streaming updates count toward my credits?","acceptedAnswer": {"@type": "Answer","text": "Yes. Each SSE price update costs one credit, like a REST call. Updates are pushed only when a swap moves the price."}},
        {"@type": "Question","name": "Can I increase the free tier limit?","acceptedAnswer": {"@type": "Answer","text": "Registering for a free API key raises 30,000 credits to 100,000. Free allowances are measured over a rolling 30-day window, not a calendar month. Pro includes 5,000,000 credits a month on the billing period."}}
      ]
    })}
</script>
