REST API errors
All REST API errors return a JSON object with amessage field (and sometimes an error field). Here’s every status code you can encounter:
200 Success
Normal response. Parse the JSON body. One important edge case: batch pricing (GET /networks/{network}/multi/prices) returns HTTP 200 with an empty array [] when none of the requested tokens have pricing data. This is not an error. It means the tokens were processed but none had prices.
400 Bad Request
The request was malformed or contained invalid parameters. The body names the offending parameter and, where there is a fixed set, lists the accepted values:- Invalid
order_byon/networks/{network}/pools/search. The accepted values arevolume_usd_24h,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_1handprice_change_percentage_5m. The oldervolume_usdspelling is rejected - Invalid
order_byon/networks/{network}/tokens/search, which takes a different list:volume_usd_24h,volume_usd_7d,volume_usd_30d,liquidity_usd,txns_24h,price_change_percentage_24h,created_atandfdv_usd - Sorting tokens by price. Do not read
price_usdout of the token 400 body and retry with it. That value appears in the message, andorder_by=price_usdon either token search path answers with a second400. Ordering tokens by raw price is not supported. Sort byvolume_usd_24horliquidity_usdinstead and readprice_usdoff the rows you get back. The eight values listed above are the ones that actually return200 - Sorting tokens by a short price change window. The 6h, 1h and 5m windows exist on pool search only, so passing one as
order_byto either token search endpoint returns a400 - Using an unknown parameter name. Unknown names are silently dropped rather than rejected, so a request with
sort_by=orvolume_24h_min=returns 200 with default ordering and no filter applied. Check the echoedqueryobject in the response to see what the API actually used - Invalid
intervalvalue for OHLCV (must be one of:1m,5m,10m,15m,30m,1h,6h,12h,24h) - Batch pricing with more than 10 tokens
- Batch pricing with zero tokens (empty
tokensparameter) - Invalid UNIX timestamp format in filter parameters
- Missing required parameters (e.g.,
startfor OHLCV)
404 Not Found
The requested resource doesn’t exist.- Invalid network ID (e.g.,
ethinstead ofethereum,solinstead ofsolana) - Token address doesn’t exist on that network
- Pool address doesn’t exist on that network
- Typo in the URL path
- Verify the network ID by checking
GET /networks - Use
GET /search?query={name}to find the correct network and address - Check that the address format matches the chain (e.g.,
0x...for EVM chains, base58 for Solana)
410 Gone
The endpoint has been permanently removed. The body names its own replacement:410 Gone):
GET /pools: useGET /pools/searchinstead.GET /networks/{network}/pools: useGET /networks/{network}/pools/searchinstead.GET /networks/{network}/pools/filter: useGET /networks/{network}/pools/searchinstead.GET /networks/{network}/dexes/{dex}/pools: useGET /networks/{network}/pools/search?dex_name={dex}instead.GET /networks/{network}/tokens/{token_address}/pools: useGET /networks/{network}/pools/search?token_address={token_address}instead.GET /networks/{network}/tokens/filter: useGET /networks/{network}/tokens/searchinstead.GET /networks/{network}/tokens/top: useGET /networks/{network}/tokens/searchinstead.
/networks/{network}/dexes/{dex}/pools returns the same 410, not a 404, which is how you tell a removed endpoint from a bad identifier.
401 Unauthorized
TheAuthorization header is missing, or its value is not a valid key.
The key goes in the header on its own, with no scheme word in front of it. This
is the single most common cause of a 401 here, because almost every other API
expects the opposite.
api-pro.dexpaprika.com sits behind an edge rule that can reject a request
before it reaches the API, answering HTTP 403 with an HTML page rather than the JSON
error above. If you get an HTML body from an API that otherwise always answers JSON,
check the header format and the base URL first, before you start regenerating the key.
What to do: send the key as the entire header value, starting with api_. If you
are using an SDK or an HTTP client that prepends a scheme word for you, which many do
when you fill in a token field, set a raw header instead.
A key that is correct but sent to the wrong base URL returns 403,
not 401.
If you have just upgraded and this is your first call to api-pro.dexpaprika.com, start
from upgrading to Pro: the host needs an Authorization header
carrying your key on every request, including the root path.
402 Payment Required
Your monthly credit allowance is exhausted. This is not a rate limit, and retrying does not help: the allowance only refills when the period rolls over, or when you add credits. The body is structured and names the next step for your tier:resets_at is the UTC timestamp when the allowance rolls over. A 402 deliberately carries no Retry-After header, which is how you tell it apart from a 429 in code.
What to do:
- Keyless and over 50,000: register a free API key for 300,000 credits a month, no card
- On a free key and over 300,000: move to Pro for 5,000,000
- On Pro: add credits from pricing, and track what you have spent in console.dexpaprika.com
- Either way, size the workload first with plan your credit usage
403 Forbidden (wrong host)
Your key is valid, but it is being sent to the wrong base URL: free keys are served onapi.dexpaprika.com, paid keys on api-pro.dexpaprika.com. Endpoints, paths and parameters are identical on both hosts; only the base URL changes.
api.dexpaprika.com, returns the same wrong_host error pointing at api-pro.dexpaprika.com.
What to do: update the base URL in your client and retry. Nothing is wrong with the key or the plan. Upgrading to Pro has the full host and header mapping, in both directions.
429 Too Many Requests
Per-minute request rate exceeded. This is separate from the monthly credit allowance, which returns 402 instead. A 429 carries aRetry-After header giving the seconds to wait.
Free tier limit: 15 requests a minute without a key, 30 with a free key, against a monthly allowance of 50,000 credits without a key (300,000 with a free key). Pro allows 300 requests a minute against 5,000,000 credits.
What to do:
- Retry after the number of seconds in
Retry-After - Cache responses for data that changes rarely (network lists, DEX lists)
- Use batch pricing instead of individual token requests. It does not reduce credits, but it does reduce HTTP calls, which is what the per-minute limit counts
- Use the streaming API for live prices instead of polling
- Consider the Pro API for 300 requests a minute
500 Internal Server Error
Something went wrong on our side. What to do: Retry with exponential backoff (wait 1s, then 2s, then 4s, etc.). If the error persists, check our Discord for status updates or contact support.Streaming API errors
The streaming API athttps://streaming.dexpaprika.com can fail in two ways: HTTP errors before the stream starts, or SSE error events during an active stream.
HTTP errors (before stream starts)
The 400 behavior is strict: In a POST request with multiple tokens, if even one token is invalid, the entire request fails. Validate all tokens via the REST API before streaming them.
SSE errors (during active stream)
If something goes wrong during an active stream, the error arrives as an SSE event:Pagination gotchas
Two styles are in play, and mixing them up is the most common migration bug. Cursor-based, which covers every search endpoint (/networks/{network}/pools/search, /pools/search, /networks/{network}/tokens/search, /tokens/search): read has_next_page and pass next_cursor back as cursor. There is no page parameter and no page_info object. Passing page here does nothing: unknown query parameters are dropped silently and you get a plausible-looking first page back every time.
Page-based, which is now only GET /networks/{network}/dexes and GET /networks/{network}/pools/{pool_address}/transactions: page=1 returns the first page and page=0 is silently treated as page=1.
Maximum page size is 100 items (via limit parameter) in both styles. Transaction pagination is limited to 100 pages; for deeper history use the cursor parameter there too.
Common mistakes and fixes
Getting empty results from pool search
Getting empty results from pool search
Symptom:
GET /networks/{network}/pools/search returns {"results": [], "has_next_page": false}Cause: Filters are too strict (for example a high volume_usd_24h_min on a quiet network), or a very small limit.Fix: Loosen the filters, or use limit=10 or higher. Note the response wraps rows in results and pages with next_cursor, not page_info.Search returns no results for a known token
Search returns no results for a known token
Symptom:
GET /search?query=USDC returns empty arrays.Cause: Search is best-effort and may not match very common/generic terms well. It searches across tokens, pools, and DEXes.Fix: Try more specific queries (e.g., the token address), or use the token endpoint directly if you know the network and address.OHLCV returns empty array
OHLCV returns empty array
Symptom: OHLCV request returns
[].Cause: The start date might be before the pool existed, or the pool may have very low activity in the requested period.Fix: Check the pool’s created_at field to ensure your date range is valid. Try a broader interval (e.g., 24h instead of 1h).Migrating from the removed pool list/filter endpoints
Migrating from the removed pool list/filter endpoints
Symptom: Code that used
/pools, /networks/{network}/pools, or /networks/{network}/pools/filter now returns 410 Gone.Cause: Those endpoints were removed. The replacement is GET /networks/{network}/pools/search (single network) or GET /pools/search (across networks).Fix: Repoint to */search and update params and response handling: volume_24h_min becomes volume_usd_24h_min, sort_by becomes order_by, sort_dir becomes sort, and page becomes cursor-based (has_next_page + next_cursor). The response wraps rows in results; each row uses id (pool address), volume_usd_24h, and transactions_24h. See the pool filtering tutorial.Migrating from the removed DEX pools endpoint
Migrating from the removed DEX pools endpoint
Symptom: Code that used Three response changes bite here. Rows come back under
/networks/{network}/dexes/{dex}/pools now returns 410 Gone.Cause: The endpoint was removed. The DEX moved out of the path and into the dex_name filter on pool search.Fix: Call GET /networks/{network}/pools/search?dex_name={dex}. dex_name takes the DEX id, the dex_id field from GET /networks/{network}/dexes, matched case-insensitively. That is what the old path segment held, so it is the value already in your code. Passing that response’s dex_name field instead, a display name like Uniswap V3, returns HTTP 200 with an empty results array rather than an error, so an empty page here usually means a display name went in where an id belonged.results, not pools. Pagination is has_next_page + next_cursor instead of page + page_info. And the 24h volume field is volume_usd_24h, with no bare volume_usd on the row; passing the old order_by=volume_usd is rejected with a 400 naming the accepted values.Streaming connection drops immediately
Streaming connection drops immediately
Symptom: Streaming connection returns 400 instantly.Cause: One or more assets in the request are invalid (wrong chain ID, non-existent token address).Fix: Validate every token via the REST API before adding it to a streaming request. In a POST batch, all assets must be valid. One bad asset cancels the entire stream.
FAQs
Does DexPaprika return rate limit headers?
Does DexPaprika return rate limit headers?
Not the draft standard
RateLimit-* family. Every response does carry X-Api-Plan, naming the plan the request was evaluated against. For counts, call GET /usage or open console.dexpaprika.com. See response headers.What happens after a rate limit reset?
What happens after a rate limit reset?
The per-minute rate frees up within the next minute; after a 429, wait the
Retry-After seconds and retry. The monthly credit allowance resets at the time given in resets_at on a 402.Are there different limits per endpoint?
Are there different limits per endpoint?
No. Every endpoint costs one credit per request, with no per-endpoint weights or compute units. The one wrinkle is batch endpoints, which charge one credit per item in the batch.