npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dexpaprika-sdk

v1.12.1

Published

JavaScript SDK for the DexPaprika API

Readme

DexPaprika SDK

npm version License: MIT

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

Developed and maintained by Coinpaprika.

Installation

npm install dexpaprika-sdk

Important: migration notices

Breaking change, unreleased: The API removed GET /networks/{network}/dexes/{dex}/pools (now HTTP 410). pools.listByDex() keeps its arguments but is backed by the unified search endpoint with a dex_name filter, so it returns the cursor-paginated shape { results, has_next_page, next_cursor } instead of { pools, page_info }.

// The call site is unchanged, the response shape is not:
const curvePools = await client.pools.listByDex('ethereum', 'curve', { limit: 10 });
console.log(curvePools.results.length, curvePools.has_next_page);

// Page with the cursor, not a page number:
if (curvePools.next_cursor) {
  const next = await client.pools.listByDex('ethereum', 'curve', {
    limit: 10,
    cursor: curvePools.next_cursor
  });
}

Rows are the search shape: read volume_usd_24h, transactions_24h and the price_change_percentage_* fields. There is no bare volume_usd and no page_info. The DEX argument accepts either the id (curve) or the display name (Curve); pass the id, which is what client.networks.getDexes() returns as dex_id.

Breaking changes in v1.6.0: The API removed the per-network list/filter REST endpoints (now HTTP 410). pools.listByNetwork(), pools.filter(), tokens.getTop(), and tokens.filter() now call the unified search endpoints and return the cursor-paginated shape { results, has_next_page, next_cursor }. Method signatures are unchanged; legacy sort/filter values are mapped internally. See the CHANGELOG for field-level details.

// Cursor pagination (page is ignored on search endpoints):
const first = await client.pools.listByNetwork('ethereum', { limit: 10 });
console.log(first.results, first.has_next_page);
if (first.next_cursor) {
  const next = await client.pools.listByNetwork('ethereum', {
    limit: 10,
    cursor: first.next_cursor
  });
}

Breaking changes in v1.4.0: The global pools endpoint has been deprecated. All pool queries now require a network specification.

// OLD (deprecated) - will throw DeprecatedEndpointError:
const pools = await client.pools.list();

// NEW (required) - specify network:
const ethereumPools = await client.pools.listByNetwork('ethereum');
const solanaPools = await client.pools.listByNetwork('solana');

Usage

import { DexPaprikaClient } from 'dexpaprika-sdk';

// Create client
const client = new DexPaprikaClient();

// Get supported networks
const networks = await client.networks.list();
console.log(networks);

// Get top pools on Ethereum (cursor-paginated search endpoint)
const pools = await client.pools.listByNetwork('ethereum', {
  limit: 10
});
console.log(pools.results);            // pool rows
console.log(pools.has_next_page, pools.next_cursor); // pagination

// Search for tokens
const results = await client.search.search('bitcoin');
console.log(`Found ${results.tokens.length} tokens`);

Options Pattern API

The DexPaprika SDK uses an options pattern for API method parameters, which provides better flexibility, readability, and extensibility:

import { DexPaprikaClient } from 'dexpaprika-sdk';

const client = new DexPaprikaClient();

// Get top pools with sorting and cursor pagination
const pools = await client.pools.listByNetwork('ethereum', {
  limit: 10,
  sort: 'desc',
  orderBy: 'volume_usd_24h' // legacy 'volume_usd' is also accepted and mapped
});

// Get pool details with options
const poolDetails = await client.pools.getDetails(
  'ethereum', 
  '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
  { inversed: false }
);

// Get pools that contain a token (network-scoped /pools/search filter,
// cursor-paginated: rows under `results`, page via `cursor`)
const tokenPools = await client.tokens.getPools(
  'ethereum',
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  {
    limit: 5,
    sort: 'desc',
    orderBy: 'volume_usd_24h' // legacy 'volume_usd' is also accepted and mapped
  }
);

// Get OHLCV data with options
const ohlcv = await client.pools.getOHLCV(
  'ethereum',
  '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
  {
    start: '-24h',   // last 24 hours; works without a key
    limit: 24,
    interval: '1h',
    inversed: false
  }
);

Using an API key (optional)

The SDK works without a key. No signup, no card. Everything below is optional.

A free key 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.

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 apiKey beats the environment variable, and no key at all keeps the previous keyless behaviour unchanged. In a browser bundle, where there is no process, the environment is simply empty and the client stays keyless.

The key is sent as the entire Authorization value, with nothing in front of it. You never write the header yourself, so this only matters when debugging what went out.

Dev and Pro customers also pass the base URL, because the host does not change on its own. Free keys are served from the default host and sending one to the Pro host returns 403, so the switch has to be deliberate:

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

One gotcha worth knowing. On the data endpoints a key the API cannot read is ignored rather than rejected: the call returns 200 with real data and you are quietly served as an anonymous caller. To confirm a key is landing, call /usage and check the plan field; keyless means the key never arrived.

Advanced Configuration

The SDK supports automatic retry with exponential backoff and response caching, both enabled by default:

import { DexPaprikaClient } from 'dexpaprika-sdk';

// Custom configuration
const client = new DexPaprikaClient(
  'https://api.dexpaprika.com', // Default API URL
  {}, // Axios options (optional)
  {
    // Retry configuration (optional)
    retry: {
      maxRetries: 4,              // Maximum retry attempts
      delaySequenceMs: [100, 500, 1000, 5000], // Specific delay for each retry (in ms)
      retryableStatuses: [408, 429, 500, 502, 503, 504] // HTTP statuses to retry
    },
    // Cache configuration (optional)
    cache: {
      ttl: 5 * 60 * 1000,         // Time-to-live: 5 minutes
      maxSize: 1000,              // Maximum cache entries
      enabled: true               // Enable/disable caching
    }
  }
);

// Working with cache
const firstCall = await client.networks.list(); // Hits API
const secondCall = await client.networks.list(); // Uses cache

// Manual cache operations
client.clearCache();             // Clear all cached data
console.log(client.cacheSize);   // Get current cache size
client.setCacheEnabled(false);   // Temporarily disable caching

API Reference

For detailed API documentation, visit docs.dexpaprika.com

Networks & DEXes

// Networks
const networks = await client.networks.list();

// DEXes on a network
const dexes = await client.dexes.listByNetwork('ethereum', {
  limit: 10
});

Pools & Transactions

// Top pools on Ethereum (cursor-paginated; read results / has_next_page / next_cursor)
const topPools = await client.pools.listByNetwork('ethereum', {
  limit: 10,
  sort: 'desc',
  orderBy: 'volume_usd_24h'
});
console.log(`Got ${topPools.results.length} pools`);

// Fetch the next page with the returned cursor
if (topPools.has_next_page && topPools.next_cursor) {
  const nextPage = await client.pools.listByNetwork('ethereum', {
    limit: 10,
    cursor: topPools.next_cursor
  });
  console.log(`Next page: ${nextPage.results.length} pools`);
}

// Top pools on different networks
const solanaPools = await client.pools.listByNetwork('solana', { limit: 5 });
const fantomPools = await client.pools.listByNetwork('fantom', { limit: 5 });

// Pools on one DEX (cursor-paginated; the DEX travels as the dex_name filter)
const curvePools = await client.pools.listByDex('ethereum', 'curve', {
  limit: 10,
  orderBy: 'volume_usd_24h'
});
console.log(`Got ${curvePools.results.length} Curve pools`);

// Pool details
const poolDetails = await client.pools.getDetails(
  'ethereum',
  '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'
);

// Transactions from the last hour. `from` and `to` also take Unix seconds,
// RFC3339 or YYYY-MM-DD; the same shapes work for createdAfter / createdBefore
// on pools.filter() and tokens.filter().
const txs = await client.pools.getTransactions(
  'ethereum',
  '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
  { limit: 20, from: '-1h' }
);
// Each row carries created_at, token symbols, volumes and USD prices
console.log(txs.transactions[0]?.created_at, txs.transactions[0]?.price_0_usd);

OHLCV Data

For price charts:

// Price history: hourly candles for the last 24 hours
const ohlcv = await client.pools.getOHLCV(
  'ethereum', 
  '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
  {
    start: '-24h',
    interval: '1h',
    limit: 24
  }
);

start and end take a relative offset from now (-24h, -7d, -90m) as well as ISO dates and Unix timestamps. How far back you can go and how fine the candles can be depends on your plan: without a key, the last 24 hours at 1h and longer; a free key opens 7 days at 10m and longer; Dev 30 days at every interval; Pro unlimited. A request outside your plan throws an ApiError with status 403. Full table: OHLCV limits by plan.

Token OHLCV Data

tokens.getOHLCV() returns the same kind of candle as pools.getOHLCV(), but for a token rather than a single pool: USD open/high/low/close built from a volume-weighted price across every pool the token trades in on the network, with volume summed the same way. This endpoint needs a Dev or Pro plan, and requests go to api-pro.dexpaprika.com with the key as the whole Authorization value, not the default host. See "Using an API key" above for how to point the client at that host, and the pricing page for current plan details. Keyless and free keys get an ApiError with status 403.

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

const tokenOhlcv = await client.tokens.getOHLCV(
  'ethereum',
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  {
    start: '-24h',
    interval: '1h',
    limit: 24
  }
);

There is no inversed option on this endpoint, unlike pools.getOHLCV(): a token candle is already a single USD price series, so there is nothing to invert. Full reference: Get OHLCV data for a token.

Tokens

// Token details (WETH)
const token = await client.tokens.getDetails(
  'ethereum', 
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
);

// Find WETH pools (network-scoped /pools/search with token_address).
// Rows come back under `results`; page with `cursor` from `next_cursor`.
const pools = await client.tokens.getPools(
  'ethereum', 
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  {
    limit: 10,
    sort: 'desc',
    orderBy: 'volume_usd_24h'
  }
);
for (const p of pools.results) {
  console.log(p.id, p.volume_usd_24h);
}

// The removed /tokens/{address}/pools endpoint supported pair queries
// (`pairWith`); /pools/search has no equivalent, so `pairWith` is deprecated
// and ignored. To match a pair, filter client-side:
const usdc = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
const wethUsdcPools = pools.results.filter(
  p => (p.tokens ?? []).some(t => t.id === usdc)
);

Pool Filtering

Backed by the unified /networks/{network}/pools/search endpoint. Results come back as { results, has_next_page, next_cursor }; legacy sortBy values such as volume_24h are accepted and mapped to canonical fields.

// Find high-volume pools on Ethereum
const filtered = await client.pools.filter('ethereum', {
  volume24hMin: 100000,
  txns24hMin: 50,
  sortBy: 'volume_usd_24h', // legacy 'volume_24h' also accepted
  sortDir: 'desc',
  limit: 10
});
console.log(`Found ${filtered.results.length} pools matching criteria`);
// Next page: pass filtered.next_cursor as `cursor`

pools.filter() also takes price-change bounds on four windows: 24h, 6h, 1h and 5m. The values are percentages, and a negative bound is the ordinary way to ask for pools that fell.

// Pools up at least 50% in the last hour, biggest mover first
const gainers = await client.pools.filter('ethereum', {
  priceChange1hMin: 50,
  sortBy: 'price_change_percentage_1h',
  limit: 10
});

// Pools down at least 20% on the day
const losers = await client.pools.filter('ethereum', {
  priceChange24hMax: -20,
  limit: 10
});

Every window has a Min and a Max form: priceChange24hMin/Max, priceChange6hMin/Max, priceChange1hMin/Max, priceChange5mMin/Max.

Pool sort fields: volume_usd_24h, volume_usd_7d, volume_usd_30d, liquidity_usd, txns_24h, created_at, price_usd, price_change_percentage_24h, price_change_percentage_6h, price_change_percentage_1h, price_change_percentage_5m.

What the token endpoint does with the same windows

The 24h window is common to both search endpoints. tokens.filter() takes priceChange24hMin/Max, and price_change_percentage_24h is a valid token sort field.

Only the three short windows, 6h, 1h and 5m, are pools-only, and they fail in two different ways on /networks/{network}/tokens/search. As a sort value the endpoint returns HTTP 400. As a filter bound it returns 200 and ignores the parameter, which is indistinguishable from a wide filter unless you compare the page against an unfiltered one. So tokens.getTop() and tokens.filter() take neither, rather than passing along something that silently does nothing.

Top Tokens & Token Filtering

Both are backed by /networks/{network}/tokens/search and return { results, has_next_page, next_cursor }. Token rows are flat: address, volume_usd_24h, fdv_usd, txns_24h, price_change_percentage_24h, etc.

// Get top tokens by 24h volume
const topTokens = await client.tokens.getTop('ethereum', {
  orderBy: 'volume_usd_24h', // legacy 'volume_24h' also accepted
  limit: 10
});
console.log(topTokens.results.map(t => t.address));

// Filter tokens by criteria
const filtered = await client.tokens.filter('ethereum', {
  volume24hMin: 100000,
  fdvMin: 1000000,
  limit: 10
});

// Tokens up at least 20% on the day
const gainers = await client.tokens.filter('ethereum', {
  priceChange24hMin: 20,
  sortBy: 'price_change_percentage_24h',
  limit: 10
});

Batch Token Prices

// Get prices for multiple tokens in one request (max 10)
const prices = await client.tokens.getMultiPrices('ethereum', [
  '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
  '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
]);
prices.forEach(p => console.log(`${p.id}: $${p.price_usd}`));

Search & Stats

// Search
const results = await client.search.search('bitcoin');

// Stats
const stats = await client.utils.getStats();

TypeScript Types

The SDK includes TypeScript types for easier development. See the documentation for response type details.

Error Handling

The SDK includes specific error classes for better error handling:

import { 
  DexPaprikaClient, 
  DeprecatedEndpointError, 
  NetworkNotFoundError,
  PoolNotFoundError,
  ApiError 
} from 'dexpaprika-sdk';

const client = new DexPaprikaClient();

try {
  // This will throw DeprecatedEndpointError
  const pools = await client.pools.list();
} catch (error) {
  if (error instanceof DeprecatedEndpointError) {
    console.log('Migration required:', error.message);
    // Use network-specific method instead
    const pools = await client.pools.listByNetwork('ethereum');
  } else if (error instanceof NetworkNotFoundError) {
    console.log('Invalid network:', error.message);
  } else if (error instanceof PoolNotFoundError) {
    console.log('Pool not found:', error.message);
  } else {
    console.error('Other error:', error.message);
  }
}

Using the error helper:

import { parseError } from 'dexpaprika-sdk/dist/utils/helpers';

try {
  const pools = await client.pools.listByNetwork('ethereum');
  // Process results
} catch (err) {
  console.error(parseError(err));
}

Utilities

Helper functions:

import { formatVolume, formatPair } from 'dexpaprika-sdk/dist/utils/helpers';

// Format volume like $1.23M
console.log(formatVolume(1234567));  // $1.23M

// Format token pair
console.log(formatPair('ETH', 'USDC')); // ETH/USDC

Retry & Caching

You can also use the retry and caching utilities directly:

import { withRetry, Cache } from 'dexpaprika-sdk';

// Retry a function with custom settings
const result = await withRetry(
  async () => {
    // Your async operation here
    return await someAsyncFunction();
  },
  { maxRetries: 4, delaySequenceMs: [100, 200, 300, 400] }
);

// Create a standalone cache
const cache = new Cache({ ttl: 60 * 1000 }); // 1 minute TTL
cache.set('key', value);
const cachedValue = cache.get('key');

Resources

License

MIT

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a Pull Request.

Development and Testing

The SDK includes a comprehensive test suite to verify functionality:

# Run basic functionality tests
npm test

# Run real-world API tests
npm run verify:real

# Check the query the SDK builds for the search endpoints (offline, no network)
npm run test:params

# Hit the live search endpoints
npm run test:endpoints

# Pin the request listByDex puts on the wire, then check it against the live API
npm run test:dex-pools

# Run all tests sequentially
npm run test:all

The runner is tsx. It is a devDependency, so npm ci is all the setup there is.

All test files are located in the tests/ directory:

  • test-basic.ts - Basic API functionality tests
  • test-real-world.ts - Tests with actual API calls and simulated failures
  • test-search-params.ts - Offline checks on the query parameters the SDK sends to /pools/search and /tokens/search. Both endpoints answer 200 for parameters they do not recognize and ignore them, so a misspelled filter bound looks like a successful wide filter over the wire. These checks read the params off the client before the request goes out and need neither network nor market.
  • test-new-endpoints.ts - The live counterpart. Every filter check compares against an unfiltered baseline rather than trusting the status code.

Support

For issues, questions, or feedback, please:

Disclaimer

This SDK is created and maintained by Coinpaprika. While we strive to provide accurate and up-to-date data, we make no guarantees regarding the accuracy, reliability, or completeness of the data provided through the DexPaprika API.