See also: REST intro,
Networks,
Pools
Installation
go get github.com/coinpaprika/dexpaprika-sdk-go
Prerequisites
- Go 1.24 or higher
- Connection to the internet to access the DexPaprika API
- No API key needed to start
Quick Example: Get Token Price
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func main() {
// Create client
client := dexpaprika.NewClient()
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Get WETH token details on Ethereum
token, err := client.Tokens.GetDetails(ctx, "ethereum", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
if err != nil {
log.Fatalf("Error getting token details: %v", err)
}
fmt.Printf("%s: $%.2f\n", token.Name, token.PriceUSD)
// Output: Wrapped Ether: $3245.67
}
Using an API key (optional)
The SDK works without a key, and that is the default. A free key raises 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. Requires v1.8.0 or later.// Explicit
client := dexpaprika.NewClient(dexpaprika.WithAPIKey("api_your_key_here"))
// Or leave it out and set DEXPAPRIKA_API_KEY in the environment
client := dexpaprika.NewClient()
api-pro.dexpaprika.com.
The key is sent as the entire
Authorization header value. Nothing goes in front of it,
no scheme word of any kind. The SDK writes the header for you, so this matters when you are
debugging what went out or calling the API directly. See
401 Unauthorized.API Methods Reference
Parameters marked with an asterisk (*) are required.
category
Show methods
Show methods
client.Networks.List(ctx)
Endpoint: GET/networksGets all supported blockchain networks including Ethereum, Solana, etc.Parameters:ctx* - Context for API request
networks, err := client.Networks.List(ctx)
category
Show methods
Show methods
client.Networks.ListDexes(ctx, networkId, options)
Endpoint: GET/networks/{network}/dexesGets all DEXes on a specific network.Parameters:ctx* - Context for API requestnetworkId* - ID of the network (e.g., ‘ethereum’, ‘solana’)options- ListOptions containing pagination parameters:Page- Page number for pagination (starts at 0)Limit- Number of results per page
options := &dexpaprika.ListOptions{
Page: 0,
Limit: 10,
}
dexes, err := client.Networks.ListDexes(ctx, "ethereum", options)
category
Show methods
Show methods
client.Pools.List(ctx, options)
The
GET /pools endpoint was removed and returns 410 Gone. Whatever this
method does locally, the request cannot succeed. Use the network-scoped method
below and pass a network, or call GET /pools/search with a chains filter
directly. See pool filtering./pools (removed, 410 Gone)Gets top pools across all networks with pagination.Parameters:ctx* - Context for API requestoptions- ListOptions containing pagination and sorting parameters:Page- Page number for pagination (starts at 0)Limit- Number of results per pageSort- Sort direction (‘asc’ or ‘desc’)OrderBy- Field to sort by (‘volume_usd’, ‘liquidity_usd’, etc.)
options := &dexpaprika.ListOptions{
Limit: 10,
OrderBy: "volume_usd",
Sort: "desc",
}
pools, err := client.Pools.List(ctx, options)
client.Pools.ListByNetwork(ctx, networkId, options)
Endpoint: GET/networks/{network}/pools/searchGets pools on a specific network with pagination and sorting options.Parameters:ctx* - Context for API requestnetworkId* - ID of the networkoptions-ListOptions. The endpoint is cursor-paginated, so page forward withCursortaken from the previous response’sNextCursor;Pageis not sent. Legacy sort values are mapped, soOrderBy: "volume_usd"is sent asorder_by=volume_usd_24h, and REST rejects the legacy spelling with400
results array plus has_next_page and next_cursor. Response Structure.options := &dexpaprika.ListOptions{
Limit: 5,
OrderBy: "volume_usd_24h",
Sort: "desc",
}
pools, err := client.Pools.ListByNetwork(ctx, "ethereum", options)
client.Pools.ListByDex(ctx, networkId, dexId, options)
GET /networks/{network}/dexes/{dex}/pools was removed and returns 410 Gone.
This method now calls GET /networks/{network}/pools/search?dex_name=... instead. The DEX id
moved out of the path and into a filter, so Page is gone and the response shape changed.
See pool filtering./networks/{network}/pools/search?dex_name=...Gets pools on a specific DEX within a network.Parameters:ctx* - Context for API requestnetworkId* - ID of the networkdexId* - ID of the DEX, thedex_idfield fromclient.Networks.ListDexes, case-insensitive (a display name likeUniswap V3returns no rows instead of an error)options- ListOptions containingLimit,OrderBy,Sort, andCursor
ListOptions.Page is not sent for this call any more. Page through with Cursor, taking the
value from NextCursor on the previous response. The SDK normalizes legacy sort values, so
volume_usd goes out as order_by=volume_usd_24h; REST rejects the legacy spelling with a
400 that lists the values it will take.results array plus has_next_page and next_cursor. Response Structure.options := &dexpaprika.ListOptions{
Limit: 10,
OrderBy: "volume_usd_24h",
Sort: "desc",
}
pools, err := client.Pools.ListByDex(ctx, "ethereum", "uniswap_v3", options)
client.Pools.GetDetails(ctx, networkId, poolAddress, options)
Endpoint: GET/networks/{network}/pools/{pool_address}Gets detailed information about a specific pool.Parameters:ctx* - Context for API requestnetworkId* - ID of the networkpoolAddress* - On-chain address of the pooloptions- PoolDetailOptions containing:Inversed- Whether to invert the price ratio (boolean)
options := &dexpaprika.PoolDetailOptions{
Inversed: false,
}
poolDetails, err := client.Pools.GetDetails(ctx, "ethereum", "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", options)
client.Pools.GetTransactions(ctx, networkId, poolAddress, options)
Endpoint: GET/networks/{network}/pools/{pool_address}/transactionsGets transaction history for a specific pool with pagination.Parameters:ctx* - Context for API requestnetworkId* - ID of the networkpoolAddress* - On-chain address of the pooloptions- ListOptions containing pagination parameters
options := &dexpaprika.ListOptions{
Limit: 20,
Page: 0,
}
transactions, err := client.Pools.GetTransactions(ctx, "ethereum", "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", options)
client.Pools.GetOHLCV(ctx, networkId, poolAddress, options)
Endpoint: GET/networks/{network}/pools/{pool_address}/ohlcvGets OHLCV (Open, High, Low, Close, Volume) chart data for a pool.Parameters:ctx* - Context for API requestnetworkId* - ID of the networkpoolAddress* - On-chain address of the pooloptions- OHLCVOptions containing:Start* - Start time (time.Time or string ISO format)End- End time (optional)Limit- Number of data points to returnInterval- Time interval (‘1h’, ‘6h’, ‘24h’, etc.)Inversed- Whether to invert the price ratio (boolean)
// Start time 7 days ago
startTime := time.Now().AddDate(0, 0, -7)
options := &dexpaprika.OHLCVOptions{
Start: startTime,
Limit: 100,
Interval: "1h",
Inversed: false,
}
ohlcv, err := client.Pools.GetOHLCV(ctx, "ethereum", "0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc", options)
category
Show methods
Show methods
client.Tokens.GetDetails(ctx, networkId, tokenAddress)
Endpoint: GET/networks/{network}/tokens/{token_address}Gets comprehensive token information.Parameters:ctx* - Context for API requestnetworkId* - ID of the networktokenAddress* - Token contract address
token, err := client.Tokens.GetDetails(ctx, "ethereum", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
client.Tokens.GetPools(ctx, networkId, tokenAddress, options)
Endpoint: GET/networks/{network}/pools/search?token_address=...Gets pools containing a specific token.Parameters:ctx* - Context for API requestnetworkId* - ID of the networktokenAddress* - Token contract addressoptions-*TokenPoolsOptions, which embeds*ListOptionsforLimit,Sort,OrderByandCursor.Pageis not sent upstream: the endpoint is cursor-paginated, so page forward withCursortaken from the previous response’sNextCursoroptions.AdditionalTokenAddress- deprecated and no longer sent.GET /networks/{network}/pools/searchaccepts onetoken_addressonly, and repeating it makes the API use a single value rather than filtering for the pair. Filterresults[].tokensyourself if you need a specific pairoptions.Reorder- deprecated and no longer sent; the search endpoint has no equivalent
The SDK normalizes legacy sort values before they go on the wire, so
OrderBy: "volume_usd" is sent as order_by=volume_usd_24h. REST rejects the legacy spelling with 400, so use the canonical value when you call the API directly.options := &dexpaprika.TokenPoolsOptions{
ListOptions: &dexpaprika.ListOptions{
Limit: 10,
OrderBy: "volume_usd_24h",
Sort: "desc",
},
}
// Get the busiest WETH pools on Ethereum
pools, err := client.Tokens.GetPools(
ctx,
"ethereum",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
options,
)
category
Show methods
Show methods
client.Search.Search(ctx, query)
Endpoint: GET/searchSearches across tokens, pools, and DEXes using a query string.Parameters:ctx* - Context for API requestquery* - Search query string
results, err := client.Search.Search(ctx, "ethereum")
category
Show methods
Show methods
client.Utils.GetStats(ctx)
Endpoint: GET/statsGets platform-wide statistics.Parameters:ctx* - Context for API request
stats, err := client.Utils.GetStats(ctx)
Complete Example
Show example
Show example
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func main() {
// Initialize client
client := dexpaprika.NewClient()
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Get Ethereum network details
networks, err := client.Networks.List(ctx)
if err != nil {
log.Fatalf("Error fetching networks: %v", err)
}
var ethereum *dexpaprika.Network
for _, network := range networks {
if network.ID == "ethereum" {
ethereum = &network
break
}
}
if ethereum == nil {
log.Fatal("Ethereum network not found")
}
fmt.Printf("Found %s with %d DEXes\n", ethereum.DisplayName, ethereum.DexesCount)
// Get WETH token details
weth, err := client.Tokens.GetDetails(
ctx,
"ethereum",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
)
if err != nil {
log.Fatalf("Error fetching token details: %v", err)
}
fmt.Printf("%s price: $%.2f\n", weth.Name, weth.PriceUSD)
// Find the busiest WETH pools
options := &dexpaprika.TokenPoolsOptions{
ListOptions: &dexpaprika.ListOptions{
Limit: 5,
OrderBy: "volume_usd_24h",
Sort: "desc",
},
}
pools, err := client.Tokens.GetPools(
ctx,
"ethereum",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
options,
)
if err != nil {
log.Fatalf("Error fetching pools: %v", err)
}
// Show top pools. /pools/search rows carry VolumeUSD24h, not VolumeUSD
fmt.Println("Top WETH pools:")
for _, pool := range pools.Pools {
var vol float64
if pool.VolumeUSD24h != nil {
vol = *pool.VolumeUSD24h
}
fmt.Printf("%s: $%.2f 24h volume\n", pool.DexName, vol)
}
}
Advanced Features
Error Handling
Show error handling
Show error handling
import (
"context"
"errors"
"fmt"
"log"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func handleAPIErrors() {
client := dexpaprika.NewClient()
ctx := context.Background()
// Attempt to get a token with an invalid address
_, err := client.Tokens.GetDetails(ctx, "ethereum", "0xinvalidaddress")
if err != nil {
// Check for specific error types
var apiErr *dexpaprika.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 404:
fmt.Println("Token not found")
case 429:
fmt.Println("Rate limit exceeded, retry after a delay")
case 500:
fmt.Println("Server error, retry may succeed")
default:
fmt.Printf("API error: %s\n", apiErr.Message)
}
} else {
// Handle non-API errors (like network issues)
fmt.Printf("Non-API error: %v\n", err)
}
// Check if error is retryable
if dexpaprika.IsRetryable(err) {
fmt.Println("This error is retryable")
}
}
}
Caching
Show caching
Show caching
import (
"context"
"fmt"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func useCaching() {
// Create a regular client
client := dexpaprika.NewClient()
// Create a cached client with 5-minute TTL
cachedClient := dexpaprika.NewCachedClient(client, nil, 5*time.Minute)
// Create context
ctx := context.Background()
// First call - hits the API
startTime := time.Now()
networks, err := cachedClient.GetNetworks(ctx)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("First call (API): %d networks, took %v\n", len(networks), time.Since(startTime))
// Second call - served from cache (much faster)
startTime = time.Now()
networks, err = cachedClient.GetNetworks(ctx)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Second call (cached): %d networks, took %v\n", len(networks), time.Since(startTime))
}
Pagination Helpers
Show pagination
Show pagination
import (
"context"
"fmt"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func usePagination() {
client := dexpaprika.NewClient()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Create a paginator for Ethereum pools with 50 items per page
options := &dexpaprika.ListOptions{
Limit: 50,
OrderBy: "volume_usd_24h",
Sort: "desc",
}
paginator := dexpaprika.NewPoolsPaginator(client, options).ForNetwork("ethereum")
// Count total pools processed
totalPools := 0
// Process first 3 pages (or fewer if there aren't that many)
for i := 0; i < 3 && paginator.HasNextPage(); i++ {
// Get next page of results
if err := paginator.GetNextPage(ctx); err != nil {
fmt.Printf("Error getting page: %v\n", err)
break
}
// Process current page
pools := paginator.GetCurrentPage()
totalPools += len(pools)
// Process first few pools in each page
fmt.Printf("=== Page %d ===\n", i+1)
for j, pool := range pools {
if j >= 3 {
fmt.Printf("...and %d more pools\n", len(pools)-3)
break
}
var vol float64
if pool.VolumeUSD24h != nil {
vol = *pool.VolumeUSD24h
}
fmt.Printf("%s: $%.2f 24h volume\n", pool.DexName, vol)
}
}
fmt.Printf("Processed %d pools total\n", totalPools)
}
Custom Configuration
Show configuration
Show configuration
import (
"net/http"
"time"
"github.com/coinpaprika/dexpaprika-sdk-go/dexpaprika"
)
func configureClient() *dexpaprika.Client {
// Create a client with custom configuration
client := dexpaprika.NewClient(
// Custom HTTP client with longer timeout
dexpaprika.WithHTTPClient(&http.Client{
Timeout: 60 * time.Second,
}),
// Custom retry configuration (5 retries with backoff)
dexpaprika.WithRetryConfig(5, 2*time.Second, 30*time.Second),
// Rate limiting to 3 requests per second
dexpaprika.WithRateLimit(3.0),
// Custom user agent
dexpaprika.WithUserAgent("MyApp/1.0 DexPaprikaClient"),
)
return client
}
Resources
API Status
The DexPaprika API provides consistent data with stable endpoints. Requests are answered without an API key on the free tier, and a free key raises the monthly credit allowance. We aim to maintain backward compatibility and provide notice of any significant changes.FAQs
Do I need an API key with this SDK?
Do I need an API key with this SDK?
Not to start. Keyless requests work at 50,000 credits a month per IP, and a free registered key raises that to 300,000 with no card.
How do I find identifiers?
How do I find identifiers?
Use Coverage Checker or list Networks and query Tokens/Pools to discover addresses.
How do I get historical or transactions data?
How do I get historical or transactions data?
Use pools/transactions endpoints with
pool_address, network, and time/paging params as documented.What about rate limiting?
What about rate limiting?
15 requests a minute keyless, 30 with a free key 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 for how the counters work, and Pro pricing for what the 5,000,000 credit tier costs.