CoinMarketCap API Integration
CoinMarketCap API provides quotes, market data, token information, and blockchain data. The basic plan (free) gives 10,000 credits/month — enough for small projects with reasonable caching. Without caching, the limit runs out in a few days even with moderate load.
Getting API Key and Basic Setup
Register at pro.coinmarketcap.com, the key comes immediately. Base URL: https://pro-api.coinmarketcap.com/v1/. Sandbox for testing: https://sandbox-api.coinmarketcap.com/v1/ (returns fake data, key b54bcf4d-1bca-4e8e-9a24-22ff2c3d462c).
import axios, { AxiosInstance } from 'axios'
class CoinMarketCapClient {
private client: AxiosInstance
constructor(apiKey: string, sandbox = false) {
this.client = axios.create({
baseURL: sandbox
? 'https://sandbox-api.coinmarketcap.com/v1/'
: 'https://pro-api.coinmarketcap.com/v1/',
headers: {
'X-CMC_PRO_API_KEY': apiKey,
'Accept': 'application/json',
},
})
}
async getQuotes(symbols: string[]): Promise<Record<string, CmcQuote>> {
const res = await this.client.get('/cryptocurrency/quotes/latest', {
params: {
symbol: symbols.join(','),
convert: 'USD',
},
})
return res.data.data
}
async getListings(limit = 100, start = 1): Promise<CmcListing[]> {
const res = await this.client.get('/cryptocurrency/listings/latest', {
params: { limit, start, convert: 'USD', sort: 'market_cap' },
})
return res.data.data
}
}
Response Structure and Types
interface CmcQuote {
id: number
name: string
symbol: string
slug: string
circulating_supply: number
total_supply: number
max_supply: number | null
last_updated: string
quote: {
USD: {
price: number
volume_24h: number
volume_change_24h: number
percent_change_1h: number
percent_change_24h: number
percent_change_7d: number
percent_change_30d: number
market_cap: number
market_cap_dominance: number
fully_diluted_market_cap: number
last_updated: string
}
}
}
Caching: Mandatory
Each API request spends credits. One request for quotes of 10 coins = 10 credits. With 10,000 credits/month that's 1,000 requests — approximately one request every 43 minutes. Cache aggressively:
import { createClient } from 'redis'
const redis = createClient({ url: process.env.REDIS_URL })
await redis.connect()
async function getCachedQuotes(
symbols: string[],
ttlSeconds = 60
): Promise<Record<string, CmcQuote>> {
const cacheKey = `cmc:quotes:${symbols.sort().join(',')}`
const cached = await redis.get(cacheKey)
if (cached) {
return JSON.parse(cached)
}
const fresh = await cmcClient.getQuotes(symbols)
await redis.setEx(cacheKey, ttlSeconds, JSON.stringify(fresh))
return fresh
}
TTL of 60 seconds — reasonable balance for displaying prices in UI. For historical data or inactive pages — TTL 5–15 minutes.
Request Cost by Endpoint
| Endpoint | Credits/Request |
|---|---|
/quotes/latest (1 symbol) |
1 |
/quotes/latest (N symbols) |
N |
/listings/latest (100 coins) |
1 |
/listings/latest (5000 coins) |
50 |
/info (metadata, 1 coin) |
1 |
/historical (OHLCV) |
1 / data point |
/global-metrics/latest |
1 |
More cost-effective to get list via /listings/latest and cache the entire response, than to make individual requests by symbols.
Error Handling
interface CmcError {
status: {
error_code: number
error_message: string
}
}
// CoinMarketCap error codes
// 1001 - invalid API key
// 1002 - API key not active
// 1006 - plan limit exceeded
// 1007 - daily limit exceeded
// 1008 - minute limit exceeded
// 1009 - hourly limit exceeded
// 1010 - IP not in whitelist
function handleCmcError(errorCode: number): void {
if ([1008, 1009].includes(errorCode)) {
// Rate limit — exponential backoff
throw new RateLimitError('CoinMarketCap rate limit exceeded')
}
if (errorCode === 1006) {
// Credits exhausted for the month — alert team
alertTeam('CMC monthly credits exhausted')
}
}
Useful Endpoints for Typical Tasks
// Global market statistics (total market cap, BTC dominance)
GET /v1/global-metrics/quotes/latest
// Top coins by categories (DeFi, NFT, Layer 1)
GET /v1/cryptocurrency/category?id=605e72d4169be1664dc91ea3 // DeFi category ID
// Currency conversion (how much ETH for 1000 USD)
GET /v1/tools/price-conversion?amount=1000&symbol=USD&convert=ETH
// List of all supported coins with their CMC IDs (for building mapping)
GET /v1/cryptocurrency/map?listing_status=active&limit=5000
Mapping ticker → CMC ID should be cached once and updated rarely (once per day): { "BTC": 1, "ETH": 1027, "BNB": 1839, ... }. Use IDs everywhere possible — more reliable than tickers (tickers are not unique, one ticker can mean different coins).
Full integration with caching, error handling, and frontend display: 2–3 days.







