See also: REST intro,
Networks,
Pools
Installation
# Using Composer
composer require coinpaprika/dexpaprika-sdk
# From source
git clone https://github.com/coinpaprika/dexpaprika-sdk-php
cd dexpaprika-sdk-php
composer install
Prerequisites
- PHP 7.4 or higher
- Composer
ext-jsonPHP extension- Connection to the internet to access the DexPaprika API
- No API key needed to start
PHP SDK quickstart
<?php
require_once 'vendor/autoload.php';
use DexPaprika\Client;
// Create client and get WETH price on Ethereum
$client = new Client();
$weth = $client->tokens->getTokenDetails('ethereum', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2');
echo "{$weth['name']}: \${$weth['summary']['price_usd']}";
// Output: Wrapped Ether: $3245.67
Using an API key (optional)
The SDK works without a key, and that is the default. A free key raises both the per-minute request limit and the credit allowance. Current figures are on the rate limits page. Requires v1.8.0 or later.use DexPaprika\Client;
use DexPaprika\Config;
// Explicit
$config = (new Config())->setApiKey('api_your_key_here');
$client = new Client(null, null, false, $config);
// Or leave it out and set DEXPAPRIKA_API_KEY in the environment
$client = new Client();
api-pro.dexpaprika.com.
The key is sent as the entire
Authorization header value. Nothing goes in front of it,
no scheme word of any kind. The SDK writes the header for you, so this matters when you are
debugging what went out or calling the API directly. See
401 Unauthorized.API methods reference
Parameters marked with an asterisk (*) are required.
category
Show methods
Show methods
client->networks->getNetworks()
Endpoint: GET/networksGets all supported blockchain networks including Ethereum, Solana, etc.Parameters: NoneReturns: Network IDs, names, and related information. Response Structure.// Get all networks
$networks = $client->networks->getNetworks();
echo "Found " . count($networks) . " networks";
Finding a network by id
getNetworks() returns a plain list of networks, so look one up by its id.// Find Ethereum in the network list
foreach ($client->networks->getNetworks() as $network) {
if ($network['id'] === 'ethereum') {
echo "Found network: {$network['display_name']}";
}
}
category
Show methods
Show methods
client->dexes->getNetworkDexes(networkId, options)
Endpoint: GET/networks/{network}/dexesGets all DEXes on a specific network.Parameters:networkId* - ID of the network (e.g., ‘ethereum’, ‘solana’)options- Additional options:page- Page number for pagination (starts at 0)limit- Number of results per page
// Get all DEXes on Ethereum
$dexes = $client->dexes->getNetworkDexes('ethereum');
echo "Found " . count($dexes['dexes']) . " DEXes on Ethereum";
Finding a DEX by id
Match ondex_id, the value getDexPools expects. dex_name is the display name.// Find Uniswap V3 on Ethereum
$dexes = $client->dexes->getNetworkDexes('ethereum');
foreach ($dexes['dexes'] as $dex) {
if ($dex['dex_id'] === 'uniswap_v3') {
echo "Found DEX: {$dex['dex_name']}";
}
}
category
Show methods
Show methods
client->pools->getTopPools(options)
The
GET /pools endpoint was removed and returns 410 Gone. Whatever this
method does locally, the request cannot succeed. Use the network-scoped method
below and pass a network, or call GET /pools/search with a chains filter
directly. See pool filtering./pools (removed, 410 Gone)Gets top pools across all networks with pagination.Parameters:options- Additional options:page- Page number for pagination (starts at 0)limit- Number of results per pageorderBy- Field to sort by (‘volume_usd’, ‘liquidity_usd’, etc.)sort- Sort direction (‘asc’ or ‘desc’)
client->pools->getNetworkPools(networkId, options)
Endpoint: GET/networks/{network}/pools/searchGets pools on a specific network with pagination and sorting options.Parameters:networkId* - ID of the networkoptions- Additional options:limit- Number of results per pageorderBy- Field to sort by (‘volume_usd_24h’, ‘liquidity_usd’, ‘txns_24h’, and the rest of the canonical list). Legacy values are mapped, sovolume_usdis sent asorder_by=volume_usd_24h, and REST rejects the legacy spelling with400sort- Sort direction (‘asc’ or ‘desc’)cursor- Cursor for the next page, taken fromnext_cursoron the previous response. There is nopageoption: the endpoint is cursor-paginated
results array plus has_next_page and next_cursor. Response Structure.// Get top 5 pools on Ethereum by volume
$pools = $client->pools->getNetworkPools('ethereum', [
'limit' => 5,
'orderBy' => 'volume_usd_24h',
'sort' => 'desc'
]);
echo "Found " . count($pools['results']) . " pools on Ethereum";
client->dexes->getDexPools(networkId, dexId, options)
GET /networks/{network}/dexes/{dex}/pools was removed and returns 410 Gone.
This method now calls GET /networks/{network}/pools/search?dex_name=... instead. The DEX id
moved out of the path and into a filter, so page is gone and the response shape changed.
See pool filtering./networks/{network}/pools/search?dex_name=...Gets pools on a specific DEX within a network.Parameters:networkId* - ID of the networkdexId* - ID of the DEX, thedex_idfield fromgetNetworkDexes, case-insensitive (a display name likeUniswap V3returns no rows instead of an error)options- Additional options:limit- Number of results per page (max 100)orderBy- Field to sort by (‘volume_usd_24h’, ‘liquidity_usd’, ‘txns_24h’, and the rest of the canonical list)sort- Sort direction (‘asc’ or ‘desc’)cursor- Cursor for the next page, taken fromnext_cursoron the previous response
There is no
page option any more. The SDK normalizes legacy sort values, so volume_usd is
sent as order_by=volume_usd_24h; REST rejects the legacy spelling with a 400 that lists the
values it will take.results array plus has_next_page and next_cursor for cursor pagination. Response Structure.// Get the busiest Uniswap V3 pools on Ethereum
$uniswapPools = $client->dexes->getDexPools('ethereum', 'uniswap_v3', [
'limit' => 10,
'orderBy' => 'volume_usd_24h',
'sort' => 'desc'
]);
foreach ($uniswapPools['results'] as $pool) {
echo "{$pool['dex_name']}: $" . number_format($pool['volume_usd_24h'], 2) . " 24h volume\n";
}
client->pools->getPoolDetails(networkId, poolAddress, options)
Endpoint: GET/networks/{network}/pools/{pool_address}Gets detailed information about a specific pool.Parameters:networkId* - ID of the networkpoolAddress* - On-chain address of the pooloptions- Additional options:inversed- Whether to invert the price ratio (boolean)
// Get details for a specific pool (WETH/USDC on Uniswap V2)
$pool = $client->pools->getPoolDetails(
'ethereum',
'0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
['inversed' => false]
);
echo "Pool: {$pool['tokens'][0]['symbol']}/{$pool['tokens'][1]['symbol']}";
client->pools->getPoolTransactions(networkId, poolAddress, options)
Endpoint: GET/networks/{network}/pools/{pool_address}/transactionsGets transaction history for a specific pool with pagination.Needs a Dev, Pro or Enterprise key and the https://api-pro.dexpaprika.com base URL since 30 September 2026; keyless and free keys get 403. See pool transactions.Parameters:networkId* - ID of the networkpoolAddress* - On-chain address of the pooloptions- Additional options:page- Page number for paginationlimit- Number of transactions per pagecursor- Transaction ID used for cursor-based paginationfrom/to- Time window: a relative offset such as'-1h', Unix seconds, RFC3339 orYYYY-MM-DD.fromis inclusive,toexclusive; results go back 7 days at most. Needs 1.10.0 or later: earlier releases did not send these two options
// Get the latest 20 transactions for a pool
$transactions = $client->pools->getPoolTransactions(
'ethereum',
'0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
['limit' => 20]
);
$latest = $transactions['transactions'][0];
echo "Latest transaction: {$latest['id']} at {$latest['created_at']}";
// Only the last hour
$lastHour = $client->pools->getPoolTransactions(
'ethereum',
'0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
['limit' => 20, 'from' => '-1h']
);
client->pools->getPoolOHLCV(networkId, poolAddress, start, options)
Endpoint: GET/networks/{network}/pools/{pool_address}/ohlcvGets OHLCV (Open, High, Low, Close, Volume) chart data for a pool.Parameters:networkId* - ID of the networkpoolAddress* - On-chain address of the poolstart* - Start time (relative offset such as-24h, ISO date string, YYYY-MM-DD, or Unix timestamp), inside your plan’s history windowoptions- Additional options:end- End time (optional)limit- Number of data points to returninterval- Time interval (‘1m’, ‘5m’, ‘10m’, ‘15m’, ‘30m’, ‘1h’, ‘6h’, ‘12h’, ‘24h’); without a key only ‘1h’ and upinversed- Whether to invert the price ratio (boolean)
// Hourly candles for the last 24 hours, which works without a key
$ohlcv = $client->pools->getPoolOHLCV(
'ethereum',
'0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
'-24h',
[
'interval' => '1h',
'limit' => 24
]
);
echo "Received " . count($ohlcv) . " OHLCV data points";
client->pools->getPoolIndicator(networkId, poolAddress, indicator, options)
Endpoint: GET/networks/{network}/pools/{pool_address}/indicatorsComputes RSI, EMA, MACD, Bollinger Bands or VWAP from a pool’s candles. Requires SDK 1.12.0 or later.Parameters:networkId* - ID of the networkpoolAddress* - On-chain address of the poolindicator* -'rsi','ema','macd','bbands'or'vwap'options- Additional options:interval- Candle interval ('1m'to'24h', or'1d'); pass it every timestart,end,limit,cursor- Range and paging, same formats as OHLCVperiod- rsi, ema, bbands and vwapfast_period,slow_period,signal_period- macd onlystd_dev- bbands only
data, oldest first, one point per completed candle: value for rsi, ema and vwap; macd, signal and histogram for macd; upper, middle and lower for bbands. parameters echoes the settings used, defaults included, and has_next_page/next_cursor page through longer ranges. Response Structure.Works on every plan, keyless included, with the same interval and history limits as pool OHLCV (limits by plan). Tutorial: technical indicators.// Hourly RSI over the last 24 hours, which works without a key
$rsi = $client->pools->getPoolIndicator(
'ethereum',
'0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
'rsi',
['interval' => '1h', 'start' => '-24h']
);
$last = end($rsi['data']);
echo "RSI {$last['value']} at {$last['timestamp']}";
category
Show methods
Show methods
client->tokens->getTokenDetails(networkId, tokenAddress)
Endpoint: GET/networks/{network}/tokens/{token_address}Gets comprehensive token information.Parameters:networkId* - ID of the networktokenAddress* - Token contract address
// Get WETH token details
$weth = $client->tokens->getTokenDetails(
'ethereum',
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
);
echo "{$weth['name']} price: \${$weth['summary']['price_usd']}";
client->tokens->getTokenPools(networkId, tokenAddress, options)
GET /networks/{network}/tokens/{token_address}/pools was removed and returns 410 Gone.
This method now calls GET /networks/{network}/pools/search?token_address=... instead. The old
second-token address pair filter and the reorder flag have no replacement and are not sent.
See pool filtering./networks/{network}/pools/search?token_address=...Gets pools containing a specific token.Parameters:networkId* - ID of the networktokenAddress* - Token contract addressoptions- Additional options:limit- Number of results per page (max 100)sort- Sort direction (‘asc’ or ‘desc’)orderBy- Field to sort by (‘volume_usd_24h’, ‘liquidity_usd’, ‘txns_24h’, and the rest of the canonical list)cursor- Cursor for the next page, taken fromnext_cursoron the previous response
There is no
page option and no second-token address option. The endpoint is cursor-paginated,
and GET /networks/{network}/pools/search has no pair filter, so anything you pass under those
names is dropped before the request goes out. Filter results[].tokens yourself to match a pair.
The SDK also normalizes legacy sort values, so volume_usd is sent as order_by=volume_usd_24h;
REST rejects the legacy spelling with 400.results array plus has_next_page and next_cursor for cursor pagination. Response Structure.// Get the busiest WETH pools on Ethereum
$pools = $client->tokens->getTokenPools(
'ethereum',
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
[
'limit' => 5,
'orderBy' => 'volume_usd_24h',
'sort' => 'desc'
]
);
foreach ($pools['results'] as $pool) {
echo "{$pool['dex_name']}: $" . number_format($pool['volume_usd_24h'], 2) . " 24h volume\n";
}
client->tokens->findToken(networkId, tokenAddress)
Endpoint: GET/networks/{network}/tokens/{token_address}Same call as getTokenDetails, wrapped so a missing token raises
NotFoundException instead of handing you an empty payload to check.Parameters:networkId* - ID of the networktokenAddress* - Contract address of the tokenasObject- Return an object instead of an array (default:false)
getTokenDetails.// Find WETH by its contract address
try {
$token = $client->tokens->findToken(
'ethereum',
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
);
echo "Found {$token['name']} at {$token['id']}";
} catch (DexPaprika\Exception\NotFoundException $e) {
echo "Token not found";
}
client->tokens->getTokenIndicator(networkId, tokenAddress, indicator, options)
Endpoint: GET/networks/{network}/tokens/{token_address}/indicatorsThe same indicators computed from the token’s USD candles across every pool it trades in. Same options and response shape as getPoolIndicator. Requires SDK 1.12.0 or later.Needs a Dev, Pro or Enterprise key and the https://api-pro.dexpaprika.com base URL; keyless and free keys get 403, thrown as a ClientException whose getErrorData()['required_tier'] names the plan.$macd = $client->tokens->getTokenIndicator(
'ethereum',
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
'macd',
['interval' => '1h', 'start' => '-7d']
);
category
Show methods
Show methods
client->search->search(query)
Endpoint: GET/searchSearches across tokens, pools, and DEXes using a query string.Parameters:query* - Search query string
// Search for "ethereum" across all entities
$results = $client->search->search("ethereum");
echo "Found " . count($results['tokens']) . " tokens\n";
echo "Found " . count($results['pools']) . " pools\n";
echo "Found " . count($results['dexes']) . " dexes\n";
category
Show methods
Show methods
client->stats->getStats()
Endpoint: GET/statsGets platform-wide statistics.Parameters: NoneReturns: Counts of chains, DEXes, pools, and tokens indexed. Response Structure.// Get platform statistics
$stats = $client->stats->getStats();
echo "Total chains: {$stats['chains']}\n";
echo "Total DEX factories: {$stats['factories']}\n";
echo "Total pools: {$stats['pools']}\n";
echo "Total tokens: {$stats['tokens']}\n";
Complete example
Show example
Show example
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DexPaprika\Client;
use DexPaprika\Exception\DexPaprikaApiException;
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
function main() {
try {
$client = new Client();
// Networks come back as a plain list of ['id' => ..., 'display_name' => ...]
$networks = $client->networks->getNetworks();
foreach ($networks as $network) {
if ($network['id'] === 'ethereum') {
echo "{$network['display_name']} is one of " . count($networks) . " networks\n";
}
}
// Price lives under summary
$weth = $client->tokens->getTokenDetails('ethereum', WETH);
echo "{$weth['name']} price: $" . number_format($weth['summary']['price_usd'], 2) . "\n";
// Pools for a token are served by pool search. Rows sit under results,
// sorted by volume_usd_24h. There is no pair filter, so match the second
// token client-side.
$pools = $client->tokens->getTokenPools('ethereum', WETH, [
'limit' => 20,
'orderBy' => 'volume_usd_24h',
'sort' => 'desc',
]);
echo "Top WETH/USDC pools:\n";
$shown = 0;
foreach ($pools['results'] as $pool) {
$ids = array_column($pool['tokens'], 'id');
if (in_array(USDC, $ids, true) && $shown < 5) {
echo "{$pool['dex_name']}: $" . number_format($pool['volume_usd_24h'], 2) . " 24h volume\n";
$shown++;
}
}
} catch (DexPaprikaApiException $e) {
echo "API Error: {$e->getMessage()}\n";
}
}
main();
Advanced features
Error handling
Show error handling
Show error handling
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DexPaprika\Client;
use DexPaprika\Exception\DexPaprikaApiException;
use DexPaprika\Exception\NotFoundException;
use DexPaprika\Exception\RateLimitException;
use DexPaprika\Exception\ServerException;
use DexPaprika\Exception\NetworkException;
// Basic error handling
try {
$client = new Client();
$token = $client->tokens->getTokenDetails('ethereum', '0xinvalidaddress');
} catch (NotFoundException $e) {
echo "Token not found: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
echo "Rate limit exceeded: {$e->getMessage()}\n";
} catch (ServerException $e) {
echo "Server error occurred: {$e->getMessage()}\n";
} catch (NetworkException $e) {
echo "Network error: {$e->getMessage()}\n";
} catch (DexPaprikaApiException $e) {
echo "API error: {$e->getMessage()} (Code: {$e->getCode()})\n";
} catch (Exception $e) {
echo "General error: {$e->getMessage()}\n";
}
// The SDK automatically retries 429 (Too Many Requests), any 5xx
// (server errors) and connection failures
// Custom retry configuration
use DexPaprika\Config;
$config = new Config();
$config->setMaxRetries(4); // Number of retry attempts (default: 5)
$config->setRetryDelays([100, 500, 1000, 5000]); // Delay in milliseconds
$client = new Client(null, null, false, $config);
// All API requests will now use these retry settings
try {
$networks = $client->networks->getNetworks();
} catch (Exception $e) {
echo "Failed after multiple retries: {$e->getMessage()}\n";
}
Caching system
Show caching
Show caching
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DexPaprika\Client;
use DexPaprika\Cache\FilesystemCache;
// The SDK includes built-in caching capabilities
// Demonstration of cache behavior
// Create a client with default cache (1 hour TTL)
$client = new Client();
$client->setupCache();
// First call - hits the API
$startTime = microtime(true);
$networks = $client->networks->getNetworks();
$firstCallTime = microtime(true) - $startTime;
echo "First call (API): " . count($networks) . " networks, took {$firstCallTime} s\n";
// Second call - served from cache (much faster)
$startTime = microtime(true);
$networks = $client->networks->getNetworks();
$secondCallTime = microtime(true) - $startTime;
echo "Second call (cached): " . count($networks) . " networks, took {$secondCallTime} s\n";
echo "Cache speedup: " . ($firstCallTime / $secondCallTime) . "x\n";
// You can skip the cache when you need fresh data
$client->getConfig()->setCacheEnabled(false);
$freshNetworks = $client->networks->getNetworks();
$client->getConfig()->setCacheEnabled(true);
// Custom cache configuration
$cache = new FilesystemCache('/path/to/custom/cache');
$client->setupCache($cache, 300); // 5 minutes TTL
// Clear the entire cache
$client->getConfig()->getCache()->clear();
Pagination helper
Show pagination
Show pagination
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DexPaprika\Client;
function fetchAllPools($networkId, $maxPages = 10) {
$client = new Client();
$allPools = [];
$limit = 50;
$cursor = null;
// Every page is one request against your allowance, so cap the walk
for ($page = 0; $page < $maxPages; $page++) {
$options = [
'limit' => $limit,
'sort' => 'desc',
'orderBy' => 'volume_usd_24h'
];
if ($cursor !== null) {
$options['cursor'] = $cursor;
}
$response = $client->pools->getNetworkPools($networkId, $options);
$allPools = array_merge($allPools, $response['results']);
// The search endpoint is cursor-paginated, not page-numbered
if (empty($response['has_next_page']) || empty($response['next_cursor'])) {
break;
}
$cursor = $response['next_cursor'];
// Keyless allows 15 requests a minute, so pause 4 seconds between pages.
// A free key doubles the rate: https://console.dexpaprika.com
sleep(4);
}
echo "Fetched a total of " . count($allPools) . " pools on {$networkId}\n";
return $allPools;
}
// Alternative approach using built-in paginator
function fetchAllPoolsWithPaginator($networkId) {
$client = new Client();
$allPools = [];
// Create a paginator for network pools. Arguments are keyed by the
// method's parameter names; whatever is left becomes the options array.
$paginator = $client->createPaginator(
$client->pools,
'getNetworkPools',
[
'networkId' => $networkId,
'limit' => 50,
'orderBy' => 'volume_usd_24h',
'sort' => 'desc'
]
);
// Paginator is not Traversable and has no setMaxPages(), so walk it explicitly.
$page = 0;
while ($paginator->hasNextPage() && $page < 10) {
$response = $paginator->getNextPage();
$allPools = array_merge($allPools, $response['results']);
echo "Processed page {$page}, got " . count($response['results']) . " pools\n";
$page++;
}
echo "Fetched a total of " . count($allPools) . " pools on {$networkId}\n";
return $allPools;
}
// Usage example
$ethereumPools = fetchAllPools('ethereum');
// or
$ethereumPools = fetchAllPoolsWithPaginator('ethereum');
Working with objects
Show objects
Show objects
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DexPaprika\Client;
$client = new Client();
// Pass 'asObject' => true to get an object instead of an array
$pool = $client->pools->getPoolDetails(
'ethereum',
'0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', // USDC/WETH Uniswap v3 pool
['asObject' => true]
);
// Access pool properties as object properties
echo "Pool: {$pool->tokens[0]->symbol}/{$pool->tokens[1]->symbol}\n";
echo "Price: \${$pool->last_price_usd}\n";
// Time windows are keyed '24h', '6h', '1h', '30m', '15m' and '5m', so use
// the brace syntax to read them
echo "Volume (24h): \${$pool->{'24h'}->volume_usd}\n";
echo "Transactions (24h): {$pool->{'24h'}->txns}\n";
echo "1h price change: {$pool->{'1h'}->last_price_usd_change}%\n";
echo "24h price change: {$pool->{'24h'}->last_price_usd_change}%\n";
// Calls without the option keep returning arrays
$networks = $client->networks->getNetworks();
$token = $client->tokens->getTokenDetails(
'ethereum',
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
['asObject' => true]
);
echo "{$token->name} price: \${$token->summary->price_usd}\n";
Resources
API status
The DexPaprika API provides consistent data with stable endpoints. Requests are answered without an API key on the free tier, and a free key raises the credit allowance. We aim to maintain backward compatibility and provide notice of any significant changes.FAQs
Do I need an API key with this SDK?
Do I need an API key with this SDK?
Not to start. Keyless requests work at 10,000 credits per rolling 30 days per IP, and a free registered key raises that to 100,000 with no card.
How do I find identifiers?
How do I find identifiers?
Use Coverage Checker or list Networks and query Tokens/Pools to discover addresses.
How do I get historical or transactions data?
How do I get historical or transactions data?
Use pools/transactions endpoints with
pool_address, network, and time/paging params as documented. Transactions need a Dev, Pro or Enterprise key on api-pro.dexpaprika.com.What about rate limiting?
What about rate limiting?
15 requests a minute keyless, 30 with a free key and 500 on Pro, against 10,000 credits keyless and 100,000 with a free key over a rolling 30 days, or 5,000,000 a month on Pro. Retry transient HTTP errors with backoff. See rate limits for how the counters work, and Pro pricing for what the 5,000,000 credit tier costs.