> ## 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.

# DexPaprika DEX API PHP SDK: on-chain liquidity and swap data client

> The official PHP client library for the DexPaprika API, providing easy access to decentralized exchange data across multiple blockchain networks

<Tip>
  See also: [REST intro](/api-reference/introduction),
  [Networks](/api-reference/networks/get-a-list-of-available-blockchain-networks),
  [Pools](/api-reference/pools/get-a-pool-on-a-network)
</Tip>

## Installation

```bash theme={null}
# 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](https://getcomposer.org/)
* `ext-json` PHP extension
* Connection to the internet to access the DexPaprika API
* No API key needed to start

## PHP SDK Quickstart

```php theme={null}
<?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['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](https://console.dexpaprika.com)
raises the monthly credit allowance. It does not raise the per-minute request limit, which is the
same on both free tiers. Current figures are on the [rate limits page](/knowledge-base/rate-limits).

Requires v1.8.0 or later.

```php theme={null}
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();
```

An explicit key beats the environment variable, and no key at all keeps the keyless behaviour
unchanged. The host is never inferred from the key: free keys are served from the default base URL,
and only [Pro](/api-pro/introduction) moves to `api-pro.dexpaprika.com`.

<Warning>
  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](/knowledge-base/error-handling#401-unauthorized).
</Warning>

## API Methods Reference

<Note>Parameters marked with an asterisk (\*) are required.</Note>

<ResponseField name="Networks" type="category">
  <Expandable title="methods">
    ### client->networks->getNetworks()

    **Endpoint:** [GET `/networks`](/api-reference/networks/get-a-list-of-available-blockchain-networks)

    Gets all supported blockchain networks including Ethereum, Solana, etc.

    **Parameters:** None

    **Returns:** Network IDs, names, and related information. [Response Structure](/api-reference/networks/get-a-list-of-available-blockchain-networks).

    ```php theme={null}
    // Get all networks
    $networks = $client->networks->getNetworks();
    echo "Found " . count($networks) . " networks";
    ```

    ### client->networks->findNetwork(networkId)

    Gets a network by its ID.

    **Parameters:**

    * `networkId`\* - ID of the network to find (e.g., 'ethereum')

    **Returns:** The network information or null if not found.

    ```php theme={null}
    // Find Ethereum network
    $ethereum = $client->networks->findNetwork('ethereum');
    if ($ethereum) {
        echo "Found network: {$ethereum['display_name']}";
    }
    ```
  </Expandable>
</ResponseField>

<ResponseField name="DEXes" type="category">
  <Expandable title="methods">
    ### client->networks->getNetworkDexes(networkId, options)

    **Endpoint:** [GET `/networks/{network}/dexes`](/api-reference/dexes/get-a-list-of-available-dexes-on-a-network)

    Gets 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

    **Returns:** DEX IDs, names, pool counts, and volume information. [Response Structure](/api-reference/dexes/get-a-list-of-available-dexes-on-a-network).

    ```php theme={null}
    // Get all DEXes on Ethereum
    $dexes = $client->networks->getNetworkDexes('ethereum', ['limit' => 10]);
    echo "Found " . count($dexes['dexes']) . " DEXes on Ethereum";
    ```

    ### client->networks->findDex(networkId, dexId)

    Finds a specific DEX on a network by its ID.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `dexId`\* - ID of the DEX to find

    **Returns:** The DEX information or null if not found.

    ```php theme={null}
    // Find Uniswap V3 on Ethereum
    $dex = $client->networks->findDex('ethereum', 'uniswap-v3');
    if ($dex) {
        echo "Found DEX: {$dex['name']}";
    }
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Pools" type="category">
  <Expandable title="methods">
    ### client->pools->getTopPools(options)

    <Warning>
      **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](/tutorials/pool-filtering).
    </Warning>

    **Endpoint:** [GET `/pools`](/api-reference/pools/get-top-x-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 page
      * `orderBy` - Field to sort by ('volume\_usd', 'liquidity\_usd', etc.)
      * `sort` - Sort direction ('asc' or 'desc')

    **Returns:** Paginated list of pool objects with pricing data. [Response Structure](/api-reference/pools/get-top-x-pools).

    ```php theme={null}
    // Get top 10 pools by volume
    $topPools = $client->pools->getTopPools([
        'limit' => 10, 
        'orderBy' => 'volume_usd', 
        'sort' => 'desc'
    ]);
    echo "Top pool: {$topPools['pools'][0]['dex_name']}";
    ```

    ### client->pools->getNetworkPools(networkId, options)

    **Endpoint:** [GET `/networks/{network}/pools/search`](/api-reference/pools/advanced-pool-filtering-on-a-specific-network)

    Gets pools on a specific network with pagination and sorting options.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `options` - Additional options:
      * `limit` - Number of results per page
      * `orderBy` - Field to sort by ('volume\_usd\_24h', 'liquidity\_usd', 'txns\_24h', and the rest of the canonical list). Legacy values are mapped, so `volume_usd` is sent as `order_by=volume_usd_24h`, and REST rejects the legacy spelling with `400`
      * `sort` - Sort direction ('asc' or 'desc')
      * `cursor` - Cursor for the next page, taken from `next_cursor` on the previous response. There is no `page` option: the endpoint is cursor-paginated

    **Returns:** Cursor-paginated pools for the given network: a `results` array plus `has_next_page` and `next_cursor`. [Response Structure](/api-reference/pools/advanced-pool-filtering-on-a-specific-network).

    ```php theme={null}
    // 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->pools->getDexPools(networkId, dexId, options)

    <Warning>
      **`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](/tutorials/pool-filtering).
    </Warning>

    **Endpoint:** [GET `/networks/{network}/pools/search?dex_name=...`](/api-reference/pools/advanced-pool-filtering-on-a-specific-network)

    Gets pools on a specific DEX within a network.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `dexId`\* - ID of the DEX, the `dex_id` field from `getNetworkDexes`, case-insensitive (a display name like `Uniswap V3` returns 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 from `next_cursor` on the previous response

    <Note>
      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.
    </Note>

    **Returns:** A `results` array plus `has_next_page` and `next_cursor` for cursor pagination. [Response Structure](/api-reference/pools/advanced-pool-filtering-on-a-specific-network).

    ```php theme={null}
    // Get the busiest Uniswap V3 pools on Ethereum
    $uniswapPools = $client->pools->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}`](/api-reference/pools/get-a-pool-on-a-network)

    Gets detailed information about a specific pool.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `poolAddress`\* - On-chain address of the pool
    * `options` - Additional options:
      * `inversed` - Whether to invert the price ratio (boolean)

    **Returns:** Detailed pool information including tokens, volumes, liquidity, and more. [Response Structure](/api-reference/pools/get-a-pool-on-a-network).

    ```php theme={null}
    // 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}/transactions`](/api-reference/pools/get-transactions-of-a-pool-on-a-network-paging-can-be-used-up-to-100-pages)

    Gets transaction history for a specific pool with pagination.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `poolAddress`\* - On-chain address of the pool
    * `options` - Additional options:
      * `page` - Page number for pagination
      * `limit` - Number of transactions per page
      * `cursor` - Transaction ID used for cursor-based pagination

    **Returns:** List of transactions with details about tokens, amounts, and timestamps. [Response Structure](/api-reference/pools/get-transactions-of-a-pool-on-a-network-paging-can-be-used-up-to-100-pages).

    ```php theme={null}
    // Get the latest 20 transactions for a pool
    $transactions = $client->pools->getPoolTransactions(
        'ethereum',
        '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
        ['limit' => 20]
    );
    $latestTxTime = date('Y-m-d H:i:s', $transactions['transactions'][0]['block_timestamp']);
    echo "Latest transaction: {$latestTxTime}";
    ```

    ### client->pools->getPoolOHLCV(networkId, poolAddress, start, options)

    **Endpoint:** [GET `/networks/{network}/pools/{pool_address}/ohlcv`](/api-reference/pools/get-ohlcv-data-for-a-pool-pair)

    Gets OHLCV (Open, High, Low, Close, Volume) chart data for a pool.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `poolAddress`\* - On-chain address of the pool
    * `start`\* - Start time (ISO date string, YYYY-MM-DD, or Unix timestamp)
    * `options` - Additional options:
      * `end` - End time (optional)
      * `limit` - Number of data points to return
      * `interval` - Time interval ('1m', '5m', '15m', '30m', '1h', '6h', '12h', '24h')
      * `inversed` - Whether to invert the price ratio (boolean)

    **Returns:** Array of OHLCV data points for the specified time range and interval. [Response Structure](/api-reference/pools/get-ohlcv-data-for-a-pool-pair).

    ```php theme={null}
    // Get OHLCV data for the past 7 days with 1-hour intervals
    $endDate = date('Y-m-d');
    $startDate = date('Y-m-d', strtotime('-7 days'));

    $ohlcv = $client->pools->getPoolOHLCV(
        'ethereum',
        '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
        $startDate,
        [
            'end' => $endDate,
            'interval' => '1h',
            'limit' => 168  // 24 * 7 hours
        ]
    );

    echo "Received {$ohlcv} OHLCV data points";
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Tokens" type="category">
  <Expandable title="methods">
    ### client->tokens->getTokenDetails(networkId, tokenAddress)

    **Endpoint:** [GET `/networks/{network}/tokens/{token_address}`](/api-reference/tokens/get-a-tokens-latest-data-on-a-network)

    Gets comprehensive token information.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `tokenAddress`\* - Token contract address

    **Returns:** Token details including price, market cap, volume, and metadata. [Response Structure](/api-reference/tokens/get-a-tokens-latest-data-on-a-network).

    ```php theme={null}
    // Get WETH token details
    $weth = $client->tokens->getTokenDetails(
        'ethereum',
        '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
    );
    echo "{$weth['name']} price: \${$weth['price_usd']}";
    ```

    ### client->tokens->getTokenPools(networkId, tokenAddress, options)

    <Warning>
      **`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](/tutorials/pool-filtering).
    </Warning>

    **Endpoint:** [GET `/networks/{network}/pools/search?token_address=...`](/api-reference/pools/advanced-pool-filtering-on-a-specific-network)

    Gets pools containing a specific token.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `tokenAddress`\* - Token contract address
    * `options` - 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 from `next_cursor` on the previous response

    <Note>
      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`.
    </Note>

    **Returns:** A `results` array plus `has_next_page` and `next_cursor` for cursor pagination. [Response Structure](/api-reference/pools/advanced-pool-filtering-on-a-specific-network).

    ```php theme={null}
    // 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}`](/api-reference/tokens/get-a-tokens-latest-data-on-a-network)

    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 network
    * `tokenAddress`\* - Contract address of the token
    * `asObject` - Return an object instead of an array (default: `false`)

    **Returns:** Token details, the same shape as `getTokenDetails`.

    ```php theme={null}
    // 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";
    }
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Search" type="category">
  <Expandable title="methods">
    ### client->search->search(query)

    **Endpoint:** [GET `/search`](/api-reference/search/search-for-tokens-pools-and-dexes)

    Searches across tokens, pools, and DEXes using a query string.

    **Parameters:**

    * `query`\* - Search query string

    **Returns:** Matching entities from all categories (tokens, pools, DEXes). [Response Structure](/api-reference/search/search-for-tokens-pools-and-dexes).

    ```php theme={null}
    // Search for "ethereum" across all entities
    $results = $client->search->search("ethereum");

    echo "Found {$results['summary']['total_tokens']} tokens\n";
    echo "Found {$results['summary']['total_pools']} pools\n";
    echo "Found {$results['summary']['total_dexes']} dexes\n";
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Stats" type="category">
  <Expandable title="methods">
    ### client->stats->getStats()

    **Endpoint:** [GET `/stats`](/api-reference/utils/retrieve-high-level-asset-statistics)

    Gets platform-wide statistics.

    **Parameters:** None

    **Returns:** Counts of chains, DEXes, pools, and tokens indexed. [Response Structure](/api-reference/utils/retrieve-high-level-asset-statistics).

    ```php theme={null}
    // 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";
    ```
  </Expandable>
</ResponseField>

## Complete Example

<Expandable title="example">
  ```php theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use DexPaprika\Client;
  use DexPaprika\Exception\DexPaprikaApiException;

  function main() {
      try {
          // Initialize client
          $client = new Client();
          
          // Get Ethereum network details
          $networks = $client->networks->getNetworks();
          $ethereum = null;
          foreach ($networks['networks'] as $network) {
              if ($network['id'] === 'ethereum') {
                  $ethereum = $network;
                  break;
              }
          }
          echo "Found {$ethereum['display_name']} with {$ethereum['dexes_count']} DEXes\n";
          
          // Get WETH token details
          $weth = $client->tokens->getTokenDetails(
              'ethereum',
              '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
          );
          echo "{$weth['name']} price: \${$weth['price_usd']}\n";
          
          // Find the busiest WETH pools
          $pools = $client->tokens->getTokenPools(
              'ethereum',
              '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',  // WETH
              [
                  'limit' => 5,
                  'orderBy' => 'volume_usd_24h',
                  'sort' => 'desc'
              ]
          );
          
          // Show top pools
          echo "Top WETH pools:\n";
          foreach ($pools['results'] as $pool) {
              echo "{$pool['dex_name']}: $" . number_format($pool['volume_usd_24h'], 2) . " 24h volume\n";
          }
      } catch (DexPaprikaApiException $e) {
          echo "API Error: {$e->getMessage()}\n";
      } catch (Exception $e) {
          echo "Error: {$e->getMessage()}\n";
      }
  }

  main();
  ```
</Expandable>

## Advanced Features

### Error Handling

<Expandable title="error handling">
  ```php theme={null}
  <?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. Try again in: {$e->getRetryAfter()} seconds\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 on these status codes:
  // 408 (Request Timeout), 429 (Too Many Requests),
  // 500, 502, 503, 504 (Server Errors)

  // Custom retry configuration
  use DexPaprika\Config;

  $config = new Config();
  $config->setMaxRetries(4);  // Number of retry attempts (default: 3)
  $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";
  }
  ```
</Expandable>

### Caching System

<Expandable title="caching">
  ```php theme={null}
  <?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();
  ```
</Expandable>

### Pagination Helper

<Expandable title="pagination">
  ```php theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use DexPaprika\Client;

  function fetchAllPools($networkId) {
      $client = new Client();
      $allPools = [];
      $limit = 50;
      $cursor = null;
      
      while (true) {
          $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
      $paginator = $client->createPaginator(
          $client->pools,
          'getNetworkPools',
          [
              $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');
  ```
</Expandable>

### Working with Objects

<Expandable title="objects">
  ```php theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use DexPaprika\Client;
  use DexPaprika\Config;

  // Create a client that returns objects instead of arrays
  $config = new Config();
  $config->setResponseFormat('object');
  $client = new Client(null, null, true, $config);

  // Get pool details
  $pool = $client->pools->getPoolDetails(
      'ethereum',
      '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'  // USDC/WETH Uniswap v3 pool
  );

  // Access pool properties as object properties
  echo "Pool: {$pool->tokens[0]->symbol}/{$pool->tokens[1]->symbol}\n";
  echo "Volume (24h): \${$pool->day->volume_usd}\n";
  echo "Transactions (24h): {$pool->day->txns}\n";
  echo "Price: \${$pool->last_price_usd}\n";

  // Time interval data is available for multiple timeframes
  echo "1h price change: {$pool->hour1->last_price_usd_change}%\n";
  echo "24h price change: {$pool->day->last_price_usd_change}%\n";

  // Combining with array-based response for specific API calls
  $client->getConfig()->setResponseFormat('array');
  $networks = $client->networks->getNetworks();

  // Back to object mode
  $client->getConfig()->setResponseFormat('object');
  $token = $client->tokens->getTokenDetails('ethereum', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2');
  echo "{$token->name} price: \${$token->price_usd}\n";
  ```
</Expandable>

## Resources

* [GitHub Repository](https://github.com/coinpaprika/dexpaprika-sdk-php)
* [DexPaprika Website](https://dexpaprika.com)
* [API Reference](/api-reference/introduction)
* [Discord Community](https://discord.gg/DhJge5TUGM)

## 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 monthly credit allowance. We aim to maintain backward compatibility and provide notice of any significant changes.

### FAQs

<AccordionGroup>
  <Accordion title="Do I need an API key with this SDK?">
    Not to start. Keyless requests work at 50,000 credits a month per IP, and a [free registered key](https://console.dexpaprika.com/dashboard) raises that to 300,000 with no card.
  </Accordion>

  <Accordion title="How do I find identifiers?">
    Use Coverage Checker or list Networks and query Tokens/Pools to discover addresses.
  </Accordion>

  <Accordion title="How do I get historical or transactions data?">
    Use pools/transactions endpoints with `pool_address`, `network`, and time/paging params as documented.
  </Accordion>

  <Accordion title="What about rate limiting?">
    15 requests a minute keyless, 50 with a [free key](https://console.dexpaprika.com) and 300 on Pro, against a monthly allowance of 50,000 credits keyless, 300,000 with a free key, or 5,000,000 on Pro. Retry transient HTTP errors with backoff. See [rate limits](/knowledge-base/rate-limits) for how the counters work, and [Pro pricing](https://dexpaprika.com/api/pricing) for what the 5,000,000 credit tier costs.
  </Accordion>
</AccordionGroup>

<script type="application/ld+json">
  {JSON.stringify({
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {"@type": "Question", "name": "Do I need an API key with this SDK?", "acceptedAnswer": {"@type": "Answer", "text": "Not to start. Keyless requests work at 50,000 credits a month per IP, and a free registered key raises that to 300,000 with no card."}},
        {"@type": "Question", "name": "How do I find identifiers?", "acceptedAnswer": {"@type": "Answer", "text": "Use Coverage Checker or list Networks and query Tokens/Pools to discover addresses."}},
        {"@type": "Question", "name": "How do I get historical or transactions data?", "acceptedAnswer": {"@type": "Answer", "text": "Use pools/transactions endpoints with pool_address, network, and time/paging params as documented."}},
        {"@type": "Question", "name": "What about rate limiting?", "acceptedAnswer": {"@type": "Answer", "text": "15 requests a minute keyless, 50 with a free key from https://console.dexpaprika.com and 300 on Pro, against a monthly allowance of 50,000 credits keyless, 300,000 with a free key, or 5,000,000 on Pro. Retry transient HTTP errors with backoff."}}
      ]
    })}
</script>
