> ## 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 TypeScript SDK: on-chain liquidity and swap data client

> JavaScript client library for accessing 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>

## Prerequisites

* Node.js 14.0.0 or higher
* Connection to the internet to access the DexPaprika API
* No API key needed to start

## Installation

Install the DexPaprika SDK using your preferred package manager:

```bash theme={null}
# using npm
npm install dexpaprika-sdk

# using yarn
yarn add dexpaprika-sdk

# using pnpm
pnpm add dexpaprika-sdk
```

## Quick example

```javascript theme={null}
import { DexPaprikaClient } from 'dexpaprika-sdk';

// Initialize the client
const client = new DexPaprikaClient();

// Get the price of Wrapped Ether (WETH) on Ethereum
async function getWethPrice() {
  const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
  const token = await client.tokens.getDetails('ethereum', wethAddress);
  console.log(`Current WETH price: $${token.price_usd}`);
}

getWethPrice();
```

## 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 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 1.10.0 or later.

```typescript theme={null}
import { DexPaprikaClient } from 'dexpaprika-sdk';

// Explicit
const client = new DexPaprikaClient('https://api.dexpaprika.com', {}, {
  apiKey: 'api_your_key_here',
});

// Or leave it out and set DEXPAPRIKA_API_KEY in the environment
const client = new DexPaprikaClient();
```

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

All API methods in the DexPaprika SDK follow a consistent pattern, accepting required parameters first, followed by an optional `options` object for additional configuration. This options pattern provides flexibility while keeping the API clean and easy to use.

For example, most listing methods accept pagination and sorting options:

```javascript theme={null}
// Get pools with custom pagination and sorting
const pools = await client.pools.listByNetwork('ethereum', {
  page: 0,       // start at first page
  limit: 20,     // get 20 results
  sort: 'desc',  // sort descending
  orderBy: 'volume_usd' // sort by volume
});
```

<ResponseField name="Networks" type="category">
  <Expandable title="Network methods">
    ### client.networks.list()

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

    Retrieves all supported blockchain networks and their metadata.

    **Parameters:** None

    **Returns:** Array of network objects containing network ID, name, and other information.

    ```javascript theme={null}
    const networks = await client.networks.list();
    console.log(`Supported networks: ${networks.length}`);
    ```
  </Expandable>
</ResponseField>

<ResponseField name="DEXes" type="category">
  <Expandable title="DEX methods">
    ### client.dexes.listByNetwork(networkId, options)

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

    Retrieves all DEXes on a specific network.

    **Parameters:**

    * `networkId`\* - Network ID (e.g., "ethereum", "solana")
    * `options` - Optional configuration:
      * `page` - Page number for pagination (defaults to 0)
      * `limit` - Number of DEXes per page (defaults to 10)

    **Returns:** Paginated list of DEX objects with name, ID, and metadata.

    ```javascript theme={null}
    const dexes = await client.dexes.listByNetwork('ethereum', { limit: 20 });
    dexes.dexes.forEach(dex => console.log(dex.dex_name));
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Pools" type="category">
  <Expandable title="Pool methods">
    ### client.pools.list(options)

    <Warning>
      **Removed.** The `GET /pools` endpoint returns `410 Gone`, and this method throws
      `DeprecatedEndpointError` rather than making a request. Use
      `client.pools.listByNetwork(network, options)` and pass a network.
    </Warning>

    ***

    ### client.pools.listByNetwork(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 cursor pagination and sorting options.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `options` - Options object for pagination and sorting:
      * `limit` - Number of pools per page
      * `sort` - Sort direction ('asc' or 'desc')
      * `orderBy` - Field to sort by ('volume\_usd', 'price\_usd', etc.). Legacy values are mapped to the canonical sort fields.
      * `cursor` - Cursor for the next page, taken from `next_cursor` on the previous response

    **Returns:** `results` array plus `has_next_page` and `next_cursor` for cursor pagination.

    ```javascript theme={null}
    const ethereumPools = await client.pools.listByNetwork('ethereum', {
      limit: 5,
      orderBy: 'volume_usd_24h',
      sort: 'desc'
    });

    console.log(`Top pool volume: $${ethereumPools.results[0].volume_usd_24h}`);

    if (ethereumPools.has_next_page) {
      const nextPage = await client.pools.listByNetwork('ethereum', {
        limit: 5,
        cursor: ethereumPools.next_cursor
      });
    }
    ```

    ***

    ### client.pools.listByDex(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 `client.dexes.listByNetwork()`, case-insensitive (a display name like `Uniswap V3` returns no rows instead of an error)
    * `options` - Options object for pagination and sorting:
      * `limit` - Number of pools 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 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.

    ```javascript theme={null}
    const uniswapPools = await client.pools.listByDex('ethereum', 'uniswap_v3', {
      limit: 10,
      orderBy: 'volume_usd_24h',
      sort: 'desc'
    });

    for (const pool of uniswapPools.results) {
      console.log(`${pool.dex_name}: $${pool.volume_usd_24h.toLocaleString()} 24h volume`);
    }
    ```

    ***

    ### client.pools.getDetails(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` - Options object:
      * `inversed` - Whether to invert the price ratio (boolean)

    **Returns:** Detailed pool information including tokens, volumes, liquidity, and more.

    ```javascript theme={null}
    // Get details for a specific pool (WETH/USDC on Uniswap V2)
    const pool = await client.pools.getDetails(
      'ethereum', 
      '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
      { inversed: false }
    );
    console.log(`Pool: ${pool.tokens[0].symbol}/${pool.tokens[1].symbol}`);
    ```

    ***

    ### client.pools.getTransactions(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` - Options object for pagination:
      * `page` - Page number for pagination
      * `limit` - Number of transactions per page
      * `cursor` - Transaction ID for cursor-based pagination

    **Returns:** List of transactions with details about tokens, amounts, and timestamps.

    ```javascript theme={null}
    // Get the latest 20 transactions for a pool
    const transactions = await client.pools.getTransactions(
      'ethereum',
      '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
      { limit: 20 }
    );

    console.log(`Latest transaction: ${transactions.transactions[0].id}`);
    ```

    ***

    ### client.pools.getOHLCV(networkId, poolAddress, 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
    * `options`\* - OHLCV options object:
      * `start`\* - Start time (ISO date string or timestamp)
      * `end` - End time (optional)
      * `limit` - Number of data points to return
      * `interval` - Time interval ('1h', '6h', '24h', etc.)
      * `inversed` - Whether to invert the price ratio (boolean)

    **Returns:** Array of OHLCV data points for the specified time range and interval.

    ```javascript theme={null}
    // Get hourly price data for the past week
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - 7);

    const ohlcvData = await client.pools.getOHLCV(
      'ethereum',
      '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
      {
        start: startDate.toISOString(),
        interval: '1h',
        limit: 168 // 7 days * 24 hours
      }
    );

    console.log(`Data points: ${ohlcvData.length}`);
    console.log(`Current price: ${ohlcvData[ohlcvData.length-1].close}`);
    ```
  </Expandable>
</ResponseField>

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

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

    Gets detailed information about a specific token on a network.

    **Parameters:**

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

    **Returns:** Detailed token information including price, volume, and metadata.

    ```javascript theme={null}
    // Get details for WETH on Ethereum
    const weth = await client.tokens.getDetails(
      'ethereum',
      '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
    );

    console.log(`${weth.name} (${weth.symbol}): $${weth.price_usd}`);
    ```

    ***

    ### client.tokens.getPools(networkId, tokenAddress, options)

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

    Gets a list of liquidity pools that include the specified token. Backed by the unified
    pool search endpoint with its `token_address` filter; the old
    `/networks/{network}/tokens/{token_address}/pools` endpoint was removed and returns `410 Gone`.

    The filter is network-scoped, so a network is always required. An unknown token address
    returns an empty result set rather than an error.

    **Parameters:**

    * `networkId`\* - ID of the network
    * `tokenAddress`\* - Token address or identifier
    * `options` - Options object for sorting and pagination:
      * `limit` - Number of pools per page
      * `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). Legacy values are mapped, so `volume_usd` is sent as `order_by=volume_usd_24h`; REST rejects the legacy spelling with `400`.
      * `cursor` - Cursor for the next page, taken from `next_cursor` on the previous response

    <Note>
      `pairWith` is no longer supported. Pool search has no pair filter, so the option is
      accepted for backwards compatibility but never sent. To find a specific pair, filter
      the returned pools on the second token yourself.
    </Note>

    **Returns:** `results` array plus `has_next_page` and `next_cursor` for cursor pagination.

    ```javascript theme={null}
    // Find the busiest WETH pools on Ethereum
    const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';

    const pools = await client.tokens.getPools(
      'ethereum',
      wethAddress,
      {
        limit: 5,
        orderBy: 'volume_usd_24h',
        sort: 'desc'
      }
    );

    pools.results.forEach(pool => {
      console.log(`${pool.dex_name}: $${pool.volume_usd_24h} 24h volume`);
    });
    ```
  </Expandable>
</ResponseField>

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

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

    Searches for tokens, pools, and DEXes by name or identifier.

    **Parameters:**

    * `query`\* - Search term (e.g., "uniswap", "bitcoin", or a token address)

    **Returns:** Search results organized by category (tokens, pools, DEXes).

    ```javascript theme={null}
    // Search for "ethereum"
    const results = await client.search.search('ethereum');

    console.log(`Found ${results.tokens.length} tokens`);
    console.log(`Found ${results.pools.length} pools`);
    console.log(`Found ${results.dexes.length} DEXes`);
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Utils" type="category">
  <Expandable title="Utility methods">
    ### client.utils.getStats()

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

    Gets high-level statistics about the DexPaprika ecosystem.

    **Parameters:** None

    **Returns:** Statistics about chains, DEXes, pools, and tokens.

    ```javascript theme={null}
    const stats = await client.utils.getStats();

    console.log(`Chains: ${stats.chains}`);
    console.log(`DEX factories: ${stats.factories}`);
    console.log(`Pools: ${stats.pools}`);
    console.log(`Tokens: ${stats.tokens}`);
    ```
  </Expandable>
</ResponseField>

## Complete example

<Expandable title="example">
  ```javascript theme={null}
  import { DexPaprikaClient } from 'dexpaprika-sdk';

  const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
  const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';

  async function main() {
    const client = new DexPaprikaClient();

    // Networks come back as a plain array of { id, display_name }
    const networks = await client.networks.list();
    const ethereum = networks.find(n => n.id === 'ethereum');
    console.log(`${ethereum.display_name} is one of ${networks.length} networks`);

    // Price lives under summary
    const weth = await client.tokens.getDetails('ethereum', WETH);
    console.log(`${weth.name} price: $${weth.summary.price_usd.toFixed(2)}`);

    // 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.
    const pools = await client.tokens.getPools('ethereum', WETH, {
      limit: 20,
      orderBy: 'volume_usd_24h',
      sort: 'desc',
    });
    const wethUsdc = pools.results.filter(p => p.tokens.some(t => t.id === USDC));

    console.log('Top WETH/USDC pools:');
    for (const pool of wethUsdc.slice(0, 5)) {
      console.log(`${pool.dex_name}: $${pool.volume_usd_24h.toLocaleString('en-US', { maximumFractionDigits: 2 })} 24h volume`);
    }
  }

  main().catch(console.error);
  ```
</Expandable>

## Advanced features

### Error handling

<Expandable title="error handling">
  ```javascript theme={null}
  import { DexPaprikaClient, parseError } from 'dexpaprika-sdk';

  // Basic error handling
  try {
    const client = new DexPaprikaClient();
    const token = await client.tokens.getDetails('ethereum', '0xinvalidaddress');
  } catch (error) {
    // Using the helper to extract the most relevant error message
    console.error('Error:', parseError(error));
    
    // Or handle specific error cases manually
    if (error.response?.status === 404) {
      console.error('Resource not found');
    } else if (error.response?.status === 429) {
      console.error('Rate limit exceeded');
    }
  }

  // The SDK automatically retries on these status codes: 
  // 408 (Request Timeout), 429 (Too Many Requests), 
  // 500, 502, 503, 504 (Server Errors)

  // Custom retry configuration
  const client = new DexPaprikaClient('https://api.dexpaprika.com', {}, {
    retry: {
      maxRetries: 3,
      delaySequenceMs: [200, 500, 1000],
      retryableStatuses: [429, 500, 503]
    }
  });
  ```
</Expandable>

### Caching

<Expandable title="caching">
  ```javascript theme={null}
  import { DexPaprikaClient, Cache } from 'dexpaprika-sdk';

  // The SDK includes built-in caching by default
  // This example shows how to configure it

  // Configure caching with custom settings
  const client = new DexPaprikaClient('https://api.dexpaprika.com', {}, {
    cache: {
      ttl: 60 * 1000, // 1 minute cache TTL (default is 5 minutes)
      maxSize: 100,   // Store up to 100 responses (default is 1000)
      enabled: true   // Enable caching (enabled by default)
    }
  });

  // Demonstration of cache behavior
  async function demonstrateCaching() {
    console.time('First call');
    await client.networks.list(); // Makes an API request
    console.timeEnd('First call');
    
    console.time('Second call');
    await client.networks.list(); // Returns cached result
    console.timeEnd('Second call');
    
    // You can also manage the cache manually
    client.clearCache();                // Clear all cached data
    console.log(client.cacheSize);      // Get current cache size
    client.setCacheEnabled(false);      // Disable caching
  }

  // Using the Cache class directly
  const manualCache = new Cache({ 
    ttl: 30 * 1000,  // 30 second TTL
    maxSize: 50      // Store maximum 50 items
  });

  manualCache.set('myKey', { data: 'example data' });
  const data = manualCache.get('myKey');
  manualCache.delete('myKey');
  manualCache.clear();
  ```
</Expandable>

### Pagination helper

<Expandable title="pagination">
  ```javascript theme={null}
  import { DexPaprikaClient } from 'dexpaprika-sdk';

  async function fetchAllPools(networkId) {
    const client = new DexPaprikaClient();
    const allPools = [];
    const limit = 50;
    let cursor;

    while (true) {
      const response = await client.pools.listByNetwork(
        networkId,
        {
          limit,
          sort: 'desc',
          orderBy: 'volume_usd_24h',
          cursor
        }
      );

      allPools.push(...response.results);

      // The search endpoint is cursor-paginated, not page-numbered
      if (!response.has_next_page || !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
      await new Promise(resolve => setTimeout(resolve, 4000));
    }

    console.log(`Fetched a total of ${allPools.length} pools on ${networkId}`);
    return allPools;
  }

  // Usage example
  fetchAllPools('ethereum').catch(console.error);
  ```
</Expandable>

### Custom configuration

<Expandable title="configuration">
  ```javascript theme={null}
  import { DexPaprikaClient } from 'dexpaprika-sdk';
  import axios from 'axios';

  // Create a custom axios instance
  const axiosInstance = axios.create({
    timeout: 60000, // 60 second timeout
    headers: {
      'User-Agent': 'MyApp/1.0 DexPaprikaSDK'
    }
  });

  // Create client with custom configuration
  const client = new DexPaprikaClient(
    'https://api.dexpaprika.com', // Base URL (optional)
    axiosInstance,                // Custom axios instance (optional)
    {
      // Retry configuration (optional)
      retry: {
        maxRetries: 5,
        delaySequenceMs: [100, 500, 1000, 2000, 5000],
        retryableStatuses: [429, 500, 502, 503, 504]
      },
      
      // Cache configuration (optional)
      cache: {
        ttl: 10 * 60 * 1000, // 10 minutes TTL
        maxSize: 500,        // Store up to 500 responses
        enabled: true        // Enable caching
      }
    }
  );

  // Usage example
  async function fetchWithCustomClient() {
    try {
      const networks = await client.networks.list();
      console.log(`Fetched ${networks.length} networks with custom client`);
    } catch (err) {
      console.error('Error:', err);
    }
  }
  ```
</Expandable>

## Resources

* [GitHub Repository](https://github.com/coinpaprika/dexpaprika-sdk-ts)
* [DexPaprika Website](https://dexpaprika.com)
* [API Reference](/api-reference/introduction)

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

<AccordionGroup>
  <Accordion title="Do I need an API key with this SDK?">
    Not to start. Keyless requests work at 30,000 credits per rolling 30 days per IP, and a [free registered key](https://console.dexpaprika.com/dashboard) raises that to 100,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, 30 with a [free key](https://console.dexpaprika.com) and 500 on Pro, against 30,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](/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 30,000 credits per rolling 30 days per IP, and a free registered key raises that to 100,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, 30 with a free key from https://console.dexpaprika.com and 500 on Pro, against 30,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."}}
         ]
    })}
</script>
