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

> The official Python 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 pip
pip install dexpaprika-sdk

# Using poetry
poetry add dexpaprika-sdk

# From source
git clone https://github.com/coinpaprika/dexpaprika-sdk-python
cd dexpaprika-sdk-python
pip install -e .
```

## Prerequisites

* Python 3.8 or higher
* Connection to the internet to access the DexPaprika API
* No API key needed to start

## Quick example: get token price

```python theme={null}
from dexpaprika_sdk import DexPaprikaClient
from dexpaprika_sdk.models import TokenDetails  # Type hint example

# Create client and get WETH price on Ethereum
client = DexPaprikaClient()
token: TokenDetails = client.tokens.get_details("ethereum", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
print(f"{token.name}: ${token.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 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 0.9.0 or later.

```python theme={null}
from dexpaprika_sdk import DexPaprikaClient

# Explicit
client = DexPaprikaClient(api_key="api_your_key_here")

# Or leave it out and set DEXPAPRIKA_API_KEY in the environment
client = 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

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

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

    **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).

    ```python theme={null}
    # Get all networks
    networks = client.networks.list()
    print(f"Found {len(networks)} networks")
    ```
  </Expandable>
</ResponseField>

<ResponseField name="DEXes" type="category">
  <Expandable title="methods">
    ### client.dexes.list\_by\_network(network\_id, page, limit)

    **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:**

    * `network_id`\* - ID of the network (e.g., 'ethereum', 'solana')
    * `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).

    ```python theme={null}
    # Get all DEXes on Ethereum
    dexes = client.dexes.list_by_network("ethereum")
    print(f"Found {len(dexes.dexes)} DEXes on Ethereum")
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Pools" type="category">
  <Expandable title="methods">
    ### client.pools.list(page, limit, sort, order\_by)

    <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-pools) (removed, `410 Gone`)

    Gets top pools across all networks with pagination.

    **Parameters:**

    * `page` - Page number for pagination (starts at 0)
    * `limit` - Number of results per page
    * `sort` - Sort direction ('asc' or 'desc')
    * `order_by` - Field to sort by ('volume\_usd', 'liquidity\_usd', etc.)

    ***

    ### client.pools.list\_by\_network(network\_id, page, limit, sort, order\_by)

    **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:**

    * `network_id`\* - ID of the network
    * `limit` - Number of results per page
    * `sort` - Sort direction ('asc' or 'desc')
    * `order_by` - 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`
    * `cursor` - Cursor for the next page, taken from `next_cursor` on the previous response. `page` is validated but never sent: 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).

    ```python theme={null}
    # Get top 5 pools on Ethereum by volume
    pools = client.pools.list_by_network(
        network_id="ethereum",
        limit=5,
        order_by="volume_usd_24h",
        sort="desc"
    )
    print(f"Found {len(pools.results)} pools on Ethereum")
    ```

    ***

    ### client.pools.list\_by\_dex(network\_id, dex\_id, limit, sort, order\_by, cursor)

    <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:**

    * `network_id`\* - ID of the network
    * `dex_id`\* - ID of the DEX, the `dex_id` field from `client.dexes.list_by_network()`, case-insensitive (a display name like `Uniswap V3` returns no rows instead of an error)
    * `limit` - Number of results per page (max 100)
    * `sort` - Sort direction ('asc' or 'desc')
    * `order_by` - 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` argument 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` list plus `has_next_page` and `next_cursor` for cursor pagination. [Response Structure](/api-reference/pools/advanced-pool-filtering-on-a-specific-network).

    ```python theme={null}
    # Get the busiest Uniswap V3 pools on Ethereum
    uniswap_pools = client.pools.list_by_dex(
        network_id="ethereum", 
        dex_id="uniswap_v3", 
        limit=10, 
        order_by="volume_usd_24h", 
        sort="desc"
    )
    for pool in uniswap_pools.results:
        print(f"{pool.dex_name}: ${pool.volume_usd_24h:,.2f} 24h volume")
    ```

    ***

    ### client.pools.get\_details(network\_id, pool\_address, inversed)

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

    Gets detailed information about a specific pool.

    **Parameters:**

    * `network_id`\* - ID of the network
    * `pool_address`\* - On-chain address of the pool
    * `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).

    ```python theme={null}
    from dexpaprika_sdk.models import PoolDetails  # Type hint example

    # Get details for a specific pool (WETH/USDC on Uniswap V2)
    pool: PoolDetails = client.pools.get_details(
        network_id="ethereum", 
        pool_address="0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", 
        inversed=False
    )
    print(f"Pool: {pool.tokens[0].symbol}/{pool.tokens[1].symbol}")
    ```

    ***

    ### client.pools.get\_transactions(network\_id, pool\_address, page, limit)

    **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:**

    * `network_id`\* - ID of the network
    * `pool_address`\* - On-chain address of the pool
    * `page` - Page number for pagination
    * `limit` - Number of transactions per page

    **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).

    ```python theme={null}
    # Get the latest 20 transactions for a pool
    transactions = client.pools.get_transactions(
        network_id="ethereum",
        pool_address="0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc",
        limit=20
    )
    latest = transactions.transactions[0]
    print(f"Latest transaction: {latest.id} in block {latest.created_at_block_number}")
    ```

    ***

    ### client.pools.get\_ohlcv(network\_id, pool\_address, start, end, limit, interval, inversed)

    **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:**

    * `network_id`\* - ID of the network
    * `pool_address`\* - On-chain address of the pool
    * `start`\* - Start time (ISO date string, YYYY-MM-DD, or Unix timestamp)
    * `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).

    ```python theme={null}
    from datetime import datetime, timedelta

    # Get OHLCV data for the past 7 days with 1-hour intervals
    end_date = datetime.now()
    start_date = end_date - timedelta(days=7)

    ohlcv = client.pools.get_ohlcv(
        network_id="ethereum",
        pool_address="0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc",
        start=start_date.strftime("%Y-%m-%d"),
        end=end_date.strftime("%Y-%m-%d"),
        interval="1h",
        limit=168  # 24 * 7 hours
    )

    print(f"Received {len(ohlcv)} OHLCV data points")
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Tokens" type="category">
  <Expandable title="methods">
    ### client.tokens.get\_details(network\_id, token\_address)

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

    Gets comprehensive token information.

    **Parameters:**

    * `network_id`\* - ID of the network
    * `token_address`\* - 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).

    ```python theme={null}
    # Get WETH token details
    weth = client.tokens.get_details(
        network_id="ethereum",
        token_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    )
    print(f"{weth.name} price: ${weth.price_usd}")
    ```

    ***

    ### client.tokens.get\_pools(network\_id, token\_address, limit, sort, order\_by, cursor)

    <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, so it still
      works. The old second-token `address` pair filter and the `reorder` flag have no replacement: pass
      either and the SDK raises a `DeprecationWarning` and drops it. 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:**

    * `network_id`\* - ID of the network
    * `token_address`\* - Token contract address
    * `limit` - Number of results per page (1 to 100)
    * `sort` - Sort direction ('asc' or 'desc')
    * `order_by` - 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. `page` is validated but never sent: the endpoint is cursor-paginated
    * `address`, `reorder` - deprecated and ignored

    **Returns:** A `PoolSearchResponse` with `results`, `has_next_page` and `next_cursor`. [Response Structure](/api-reference/pools/advanced-pool-filtering-on-a-specific-network).

    ```python theme={null}
    # Get the busiest WETH pools on Ethereum
    pools = client.tokens.get_pools(
        network_id="ethereum",
        token_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",  # WETH
        limit=5,
        order_by="volume_usd_24h",
        sort="desc",
    )

    for pool in pools.results:
        print(f"{pool.dex_name}: ${pool.volume_usd_24h:,.2f} 24h volume")
    ```
  </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).

    ```python theme={null}
    # Search for "ethereum" across all entities
    results = client.search.search("ethereum")

    print(f"Found {len(results.tokens)} tokens")
    print(f"Found {len(results.pools)} pools")
    print(f"Found {len(results.dexes)} dexes")
    ```
  </Expandable>
</ResponseField>

<ResponseField name="Utils" type="category">
  <Expandable title="methods">
    ### client.utils.get\_stats()

    **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).

    ```python theme={null}
    # Get platform statistics
    stats = client.utils.get_stats()

    print(f"Total chains: {stats.chains}")
    print(f"Total DEX factories: {stats.factories}")
    print(f"Total pools: {stats.pools}")
    print(f"Total tokens: {stats.tokens}")
    ```
  </Expandable>
</ResponseField>

## Complete example

<Expandable title="example">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient

  WETH = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
  USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"


  def main():
      client = DexPaprikaClient()

      # Networks come back as a list of Network(id, display_name)
      networks = client.networks.list()
      ethereum = next(n for n in networks if n.id == "ethereum")
      print(f"{ethereum.display_name} is one of {len(networks)} networks")

      # Price lives under summary
      weth = client.tokens.get_details(network_id="ethereum", token_address=WETH)
      print(f"{weth.name} price: ${weth.summary.price_usd:,.2f}")

      # 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.get_pools(
          network_id="ethereum",
          token_address=WETH,
          limit=20,
          order_by="volume_usd_24h",
          sort="desc",
      )
      weth_usdc = [p for p in pools.results if any(t.id == USDC for t in p.tokens)]

      print("Top WETH/USDC pools:")
      for pool in weth_usdc[:5]:
          print(f"{pool.dex_name}: ${pool.volume_usd_24h:,.2f} 24h volume")


  if __name__ == "__main__":
      main()
  ```
</Expandable>

## Advanced features

### Error handling

<Expandable title="error handling">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient
  import requests

  # Basic error handling
  try:
      client = DexPaprikaClient()
      token = client.tokens.get_details("ethereum", "0xinvalidaddress")
  except Exception as e:
      if "404" in str(e):
          print("Token not found")
      elif "429" in str(e):
          print("Rate limit exceeded")
      else:
          print(f"An error occurred: {e}")

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

  # Custom retry configuration
  client = DexPaprikaClient(
      max_retries=4,  # Number of retry attempts (default: 4)
      backoff_times=[0.1, 0.5, 1.0, 5.0]  # Backoff times in seconds
  )

  # All API requests will now use these retry settings
  try:
      networks = client.networks.list()
  except requests.exceptions.RetryError as e:
      print(f"Failed after multiple retries: {e}")
  ```
</Expandable>

### Caching system

<Expandable title="caching">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient
  import time

  # The SDK includes built-in caching by default
  # Demonstration of cache behavior

  # Create a regular client with default cache (5 minutes TTL)
  client = DexPaprikaClient()

  # First call - hits the API
  start_time = time.time()
  networks = client.networks.list()
  first_call_time = time.time() - start_time
  print(f"First call (API): {len(networks)} networks, took {first_call_time:.4f}s")

  # Second call - served from cache (much faster)
  start_time = time.time()
  networks = client.networks.list()
  second_call_time = time.time() - start_time
  print(f"Second call (cached): {len(networks)} networks, took {second_call_time:.4f}s")
  print(f"Cache speedup: {first_call_time / second_call_time:.1f}x")

  # You can skip the cache when you need fresh data
  fresh_networks = client.networks._get("/networks", skip_cache=True)

  # Clear the entire cache
  client.clear_cache()

  # Clear cache only for specific endpoints
  client.clear_cache(endpoint_prefix="/networks")

  # Different types of data have different cache durations:
  # - Network data: 24 hours
  # - Pool data: 5 minutes
  # - Token data: 10 minutes
  # - Statistics: 15 minutes
  # - Other data: 5 minutes (default)
  ```
</Expandable>

### Pagination helper

<Expandable title="pagination">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient
  import time

  def fetch_all_pools(network_id):
      client = DexPaprikaClient()
      all_pools = []
      limit = 50
      cursor = None

      while True:
          response = client.pools.list_by_network(
              network_id=network_id,
              limit=limit,
              sort="desc",
              order_by="volume_usd_24h",
              cursor=cursor,
          )

          all_pools.extend(response.results)

          # The search endpoint is cursor-paginated, not page-numbered
          if not response.has_next_page or not 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
          time.sleep(4)

      print(f"Fetched a total of {len(all_pools)} pools on {network_id}")
      return all_pools

  # Usage example
  ethereum_pools = fetch_all_pools("ethereum")
  ```
</Expandable>

### Parameter validation

<Expandable title="validation">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient

  # The SDK automatically validates parameters before making API requests
  client = DexPaprikaClient()

  # Invalid parameter examples will raise helpful error messages
  try:
      # Invalid network ID
      client.pools.list_by_network(network_id="", limit=5)
  except ValueError as e:
      print(e)  # "network_id is required"
      
  try:
      # Invalid sort parameter
      client.pools.list(sort="invalid_sort")
  except ValueError as e:
      print(e)  # "sort must be one of: asc, desc"
      
  try:
      # Invalid limit parameter
      client.pools.list(limit=500)
  except ValueError as e:
      print(e)  # "limit must be at most 100"
  ```
</Expandable>

### Working with models

<Expandable title="models">
  ```python theme={null}
  from dexpaprika_sdk import DexPaprikaClient
  from dexpaprika_sdk.models import PoolDetails  # Type hint example

  client = DexPaprikaClient()

  # Get pool details
  pool: PoolDetails = client.pools.get_details(
      network_id="ethereum",
      pool_address="0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"  # USDC/WETH Uniswap v3 pool
  )

  # Access pool properties with type checking and auto-completion
  print(f"Pool: {pool.tokens[0].symbol}/{pool.tokens[1].symbol}")
  print(f"Volume (24h): ${pool.day.volume_usd:.2f}")
  print(f"Transactions (24h): {pool.day.txns}")
  print(f"Price: ${pool.last_price_usd:.4f}")

  # Time interval data is available for multiple timeframes
  print(f"1h price change: {pool.hour1.last_price_usd_change:.2f}%")
  print(f"24h price change: {pool.day.last_price_usd_change:.2f}%")

  # All API responses are converted to typed Pydantic models
  # This provides automatic validation, serialization/deserialization,
  # and IDE auto-completion support through Python type hints
  ```
</Expandable>

## Resources

* [GitHub Repository](https://github.com/coinpaprika/dexpaprika-sdk-python)
* [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 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>
