Guide de développement de l'API CoinGecko Solana
Un guide complet pour intégrer l'API on-chain de CoinGecko pour Solana. Accédez aux prix des tokens en temps réel, aux données des pools DEX, aux graphiques OHLCV, à l'historique des trades et aux analyses de marché sur plus de 1 700 échanges décentralisés.
Aperçu
L'API Solana de CoinGecko fournit :
- Prix des tokens : Prix en temps réel par adresse de contrat (simple ou par lot)
- Données des pools : Informations sur les pools de liquidité, pools tendance, top pools
- Graphiques OHLCV : Données en chandelier pour l'analyse technique
- Historique des trades : Trades récents pour n'importe quel pool
- Découverte DEX : Lister tous les DEXes opérant sur Solana
- Recherche : Trouver les pools par nom de token, symbole ou adresse
- Megafilter : Filtrage avancé sur les pools, tokens et DEXes
Fonctionnalités clés
| Fonctionnalité | Description |
|---|---|
| 250+ réseaux | Support multi-chaînes incluant Solana |
| 1 700+ DEXes | Raydium, Orca, Jupiter, Meteora, Pump.fun, etc. |
| 15 M+ tokens | Couverture complète des tokens |
| Données en temps réel | Mises à jour toutes les 10-30 secondes |
| Données historiques | Graphiques OHLCV et historique des trades |
Démarrage rapide
Obtenir votre clé API
- API démo (gratuit) : Visitez coingecko.com/en/api
- API Pro (payant) : Visitez coingecko.com/en/api/pricing
Configuration de l'environnement
# .env file
COINGECKO_API_KEY=your_api_key_here
COINGECKO_API_TYPE=demo # or 'pro'
Configuration de l'API
// Configuration for both Demo and Pro APIs
const CONFIG = {
demo: {
baseUrl: 'https://api.coingecko.com/api/v3/onchain',
headerKey: 'x-cg-demo-api-key',
rateLimit: 30, // calls per minute
},
pro: {
baseUrl: 'https://pro-api.coingecko.com/api/v3/onchain',
headerKey: 'x-cg-pro-api-key',
rateLimit: 500, // calls per minute (varies by plan)
},
};
const apiType = process.env.COINGECKO_API_TYPE || 'demo';
const apiKey = process.env.COINGECKO_API_KEY;
const BASE_URL = CONFIG[apiType].baseUrl;
const HEADER_KEY = CONFIG[apiType].headerKey;
// Solana network identifier
const NETWORK = 'solana';
Récupération basique du prix des tokens
async function getTokenPrice(tokenAddress: string): Promise<number | null> {
const url = `${BASE_URL}/simple/networks/${NETWORK}/token_price/${tokenAddress}`;
const response = await fetch(url, {
headers: {
[HEADER_KEY]: apiKey,
'Accept': 'application/json',
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
return data.data?.attributes?.token_prices?.[tokenAddress] ?? null;
}
// Usage
const USDC = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
const price = await getTokenPrice(USDC);
console.log(`USDC Price: $${price}`);
Référence des endpoints de l'API
Prix simple des tokens
Obtenir les prix des tokens par adresse de contrat.
Endpoint : GET /simple/networks/{network}/token_price/{addresses}
Paramètres :
| Paramètre | Type | Requis | Description |
|-----------|------|--------|-------------|
| network | string | Oui | ID du réseau (solana) |
| addresses | string | Oui | Adresses de tokens séparées par des virgules (max 30 démo, 100 Pro) |
| include_market_cap | boolean | Non | Inclure les données de capitalisation boursière |
| include_24hr_vol | boolean | Non | Inclure le volume 24h |
| include_24hr_price_change | boolean | Non | Inclure le % de variation de prix 24h |
async function getTokenPrices(addresses: string[]): Promise<Record<string, TokenPriceData>> {
const addressList = addresses.join(',');
const url = `${BASE_URL}/simple/networks/${NETWORK}/token_price/${addressList}`;
const params = new URLSearchParams({
include_market_cap: 'true',
include_24hr_vol: 'true',
include_24hr_price_change: 'true',
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.attributes || {};
}
Données des tokens par adresse
Obtenir les informations détaillées des tokens.
Endpoint : GET /networks/{network}/tokens/{address}
Paramètres :
| Paramètre | Type | Requis | Description |
|-----------|------|--------|-------------|
| network | string | Oui | ID du réseau |
| address | string | Oui | Adresse du contrat de token |
| include | string | Non | Inclure top_pools pour les données de liquidité |
interface TokenData {
address: string;
name: string;
symbol: string;
decimals: number;
image_url: string;
price_usd: string;
fdv_usd: string;
market_cap_usd: string;
total_supply: string;
volume_usd: {
h24: string;
};
price_change_percentage: {
h24: string;
};
}
async function getTokenData(address: string): Promise<TokenData> {
const url = `${BASE_URL}/networks/${NETWORK}/tokens/${address}?include=top_pools`;
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.attributes;
}
Données multi-tokens
Récupérer plusieurs tokens par lot.
Endpoint : GET /networks/{network}/tokens/multi/{addresses}
async function getMultipleTokens(addresses: string[]): Promise<TokenData[]> {
const addressList = addresses.join(',');
const url = `${BASE_URL}/networks/${NETWORK}/tokens/multi/${addressList}`;
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
Données des pools par adresse
Obtenir les informations détaillées des pools.
Endpoint : GET /networks/{network}/pools/{address}
Paramètres :
| Paramètre | Type | Requis | Description |
|-----------|------|--------|-------------|
| include | string | Non | base_token, quote_token, dex |
| include_volume_breakdown | boolean | Non | Ventilation du volume par période |
interface PoolData {
address: string;
name: string;
pool_created_at: string;
base_token_price_usd: string;
quote_token_price_usd: string;
base_token_price_native_currency: string;
fdv_usd: string;
market_cap_usd: string;
reserve_in_usd: string;
price_change_percentage: {
m5: string;
h1: string;
h6: string;
h24: string;
};
transactions: {
m5: { buys: number; sells: number };
h1: { buys: number; sells: number };
h24: { buys: number; sells: number };
};
volume_usd: {
m5: string;
h1: string;
h6: string;
h24: string;
};
}
async function getPoolData(poolAddress: string): Promise<PoolData> {
const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}`;
const params = new URLSearchParams({
include: 'base_token,quote_token,dex',
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.attributes;
}
Pools tendance
Obtenir les pools tendance sur tous les réseaux ou filtrés par réseau.
Endpoint : GET /networks/trending_pools
Paramètres :
| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| include | string | base_token | Attributs à inclure |
| page | integer | 1 | Numéro de page |
| duration | string | 24h | 5m, 1h, 6h, 24h |
async function getTrendingPools(duration: '5m' | '1h' | '6h' | '24h' = '24h'): Promise<PoolData[]> {
const url = `${BASE_URL}/networks/trending_pools`;
const params = new URLSearchParams({
include: 'base_token,quote_token,dex,network',
duration,
page: '1',
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
// Filter for Solana pools
async function getSolanaTrendingPools(): Promise<PoolData[]> {
const allPools = await getTrendingPools();
return allPools.filter(pool => pool.network === 'solana');
}
Top pools du réseau
Obtenir les top pools par volume sur Solana.
Endpoint : GET /networks/{network}/pools
async function getTopPools(page: number = 1): Promise<PoolData[]> {
const url = `${BASE_URL}/networks/${NETWORK}/pools`;
const params = new URLSearchParams({
include: 'base_token,quote_token,dex',
page: page.toString(),
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
Rechercher des pools
Rechercher des pools par nom de token, symbole ou adresse.
Endpoint : GET /search/pools
Paramètres :
| Paramètre | Type | Description |
|-----------|------|-------------|
| query | string | Terme de recherche (nom, symbole, adresse) |
| network | string | Filtrer par réseau |
| page | integer | Numéro de page |
async function searchPools(query: string): Promise<PoolData[]> {
const url = `${BASE_URL}/search/pools`;
const params = new URLSearchParams({
query,
network: NETWORK,
include: 'base_token,quote_token,dex',
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
// Search for SOL pools
const solPools = await searchPools('SOL');
Graphique OHLCV des pools
Obtenir les données en chandelier pour l'analyse technique.
Endpoint : GET /networks/{network}/pools/{pool_address}/ohlcv/{timeframe}
Périodes : day, hour, minute
Paramètres :
| Paramètre | Type | Description |
|-----------|------|-------------|
| aggregate | integer | Agrégation en chandelier (1, 5, 15 pour minute ; 1, 4, 12 pour hour) |
| before_timestamp | integer | Timestamp Unix pour la pagination |
| limit | integer | Nombre de chandeliers (max 1 000) |
| currency | string | usd ou token |
interface OHLCVData {
timestamp: number;
open: number;
high: number;
low: number;
close: number;
volume: number;
}
async function getPoolOHLCV(
poolAddress: string,
timeframe: 'day' | 'hour' | 'minute' = 'hour',
aggregate: number = 1,
limit: number = 100
): Promise<OHLCVData[]> {
const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}/ohlcv/${timeframe}`;
const params = new URLSearchParams({
aggregate: aggregate.toString(),
limit: limit.toString(),
currency: 'usd',
});
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.attributes?.ohlcv_list?.map((candle: number[]) => ({
timestamp: candle[0],
open: candle[1],
high: candle[2],
low: candle[3],
close: candle[4],
volume: candle[5],
})) || [];
}
// Get hourly candles
const hourlyCandles = await getPoolOHLCV(poolAddress, 'hour', 1, 24);
// Get 5-minute candles
const fiveMinCandles = await getPoolOHLCV(poolAddress, 'minute', 5, 100);
Trades récents
Obtenir les trades récents d'une pool.
Endpoint : GET /networks/{network}/pools/{pool_address}/trades
interface TradeData {
block_number: number;
block_timestamp: string;
tx_hash: string;
tx_from_address: string;
from_token_amount: string;
to_token_amount: string;
price_from_in_currency_token: string;
price_to_in_currency_token: string;
price_from_in_usd: string;
price_to_in_usd: string;
kind: 'buy' | 'sell';
volume_in_usd: string;
}
async function getRecentTrades(poolAddress: string): Promise<TradeData[]> {
const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}/trades`;
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
Lister les DEXes sur Solana
Obtenir tous les échanges décentralisés sur Solana.
Endpoint : GET /networks/{network}/dexes
interface DexData {
id: string;
name: string;
}
async function getSolanaDexes(): Promise<DexData[]> {
const url = `${BASE_URL}/networks/${NETWORK}/dexes`;
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => ({
id: item.id,
name: item.attributes.name,
})) || [];
}
Megafilter (avancé)
Filtrage avancé pour les pools sur tous les réseaux, DEXes et tokens.
Endpoint : GET /pools/megafilter
Paramètres :
| Paramètre | Type | Description |
|-----------|------|-------------|
| networks | string | Filtrer par réseau(x) |
| dexes | string | Filtrer par DEX(es) |
| sort | string | Ordre de tri (ex., pool_created_at_desc) |
| min_reserve_in_usd | number | Liquidité minimale |
| min_h24_volume_usd | number | Volume 24h minimum |
async function getMegafilterPools(options: {
dexes?: string[];
minLiquidity?: number;
minVolume?: number;
sort?: string;
}): Promise<PoolData[]> {
const url = `${BASE_URL}/pools/megafilter`;
const params = new URLSearchParams({
networks: NETWORK,
page: '1',
});
if (options.dexes) {
params.set('dexes', options.dexes.join(','));
}
if (options.minLiquidity) {
params.set('min_reserve_in_usd', options.minLiquidity.toString());
}
if (options.minVolume) {
params.set('min_h24_volume_usd', options.minVolume.toString());
}
if (options.sort) {
params.set('sort', options.sort);
}
const response = await fetch(`${url}?${params}`, {
headers: { [HEADER_KEY]: apiKey },
});
const data = await response.json();
return data.data?.map((item: any) => item.attributes) || [];
}
// Get newest Pump.fun pools
const pumpfunPools = await getMegafilterPools({
dexes: ['pump-fun'],
sort: 'pool_created_at_desc',
});
// Get high-volume Raydium pools
const raydiumPools = await getMegafilterPools({
dexes: ['raydium'],
minVolume: 100000,
minLiquidity: 50000,
});
Identifiants courants des DEXes Solana
| DEX | ID | Description |
|---|---|---|
| Raydium | raydium |
Leading AMM on Solana |
| Orca | orca |
User-friendly DEX |
| Jupiter | jupiter |
Aggregator with pools |
| Meteora | meteora |
Dynamic AMM |
| Pump.fun | pump-fun |
Memecoin launchpad |
| OpenBook | openbook |
Order book DEX |
| Lifinity | lifinity |
Proactive market maker |
| Phoenix | phoenix |
On-chain order book |
Adresses de tokens courants
| Token | Adresse |
|---|---|
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| SOL (Wrapped) | So11111111111111111111111111111111111111112 |
| JUP | JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN |
| BONK | DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 |
| WIF | EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm |
| PYTH | HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3 |
| RAY | 4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R |
| ORCA | orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE |
Limites de débit
| Plan | Appels/minute | Max adresses/requête |
|---|---|---|
| Démo (gratuit) | 30 | 30 |
| Analyst | 500 | 50 |
| Lite | 500 | 50 |
| Pro | 1 000 | 100 |
| Enterprise | Personnalisé | Personnalisé |
Gestion des limites de débit
class RateLimiter {
private calls: number[] = [];
private maxCalls: number;
private windowMs: number = 60000; // 1 minute
constructor(maxCallsPerMinute: number) {
this.maxCalls = maxCallsPerMinute;
}
async waitForSlot(): Promise<void> {
const now = Date.now();
this.calls = this.calls.filter(t => now - t < this.windowMs);
if (this.calls.length >= this.maxCalls) {
const oldestCall = this.calls[0];
const waitTime = this.windowMs - (now - oldestCall);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.calls.push(Date.now());
}
}
// Usage
const rateLimiter = new RateLimiter(30); // Demo API
async function fetchWithRateLimit(url: string): Promise<any> {
await rateLimiter.waitForSlot();
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
return response.json();
}
Gestion des erreurs
async function safeApiCall<T>(url: string): Promise<T | null> {
try {
const response = await fetch(url, {
headers: { [HEADER_KEY]: apiKey },
});
if (response.status === 401) {
throw new Error('Invalid API key');
}
if (response.status === 429) {
throw new Error('Rate limit exceeded - wait before retrying');
}
if (response.status === 404) {
console.warn('Resource not found');
return null;
}
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
} catch (error) {
console.error('CoinGecko API error:', error);
throw error;
}
}
Codes d'erreur courants
| Code | Signification | Solution |
|---|---|---|
| 401 | Clé API invalide | Vérifier votre clé API |
| 429 | Limite de débit dépassée | Attendre et relancer, ou augmenter le plan |
| 404 | Ressource non trouvée | Vérifier l'adresse/ID réseau |
| 500+ | Erreur serveur | Relancer avec backoff exponentiel |
Bonnes pratiques
Sécurité
- Ne jamais valider les clés API vers git
- Utiliser des variables d'environnement
- Rotation des clés périodiquement
- Utiliser des clés séparées pour dev/prod
Performance
- Regrouper les requêtes de tokens si possible
- Mettre en cache les données fréquemment accessibles
- Utiliser les bonnes périodes pour l'OHLCV
- Implémenter une mise en file d'attente des requêtes pour les limites de débit
Qualité des données
- Vérifier les données de capitalisation boursière (peut être null si non vérifié)
- Vérifier la liquidité des pools avant de faire confiance aux prix
- Utiliser plusieurs périodes pour l'analyse des prix
- Surveiller le timestamp du dernier trade pour l'activité
Ressources
Structure des compétences
coingecko/
├── SKILL.md # This file
├── resources/
│ ├── api-reference.md # Complete API endpoint reference
│ ├── network-dex-ids.md # Solana network and DEX identifiers
│ └── token-addresses.md # Common Solana token addresses
├── examples/
│ ├── token-prices/
│ │ └── get-token-price.ts # Token price examples
│ ├── pools/
│ │ └── pool-data.ts # Pool data examples
│ ├── ohlcv/
│ │ └── ohlcv-charts.ts # OHLCV chart examples
│ ├── trades/
│ │ └── recent-trades.ts # Trade history examples
│ └── integration/
│ └── full-client.ts # Complete client example
├── templates/
│ └── coingecko-client.ts # Production-ready client template
└── docs/
└── troubleshooting.md # Common issues and solutions
Vérifier
- Un appel RPC/SDK réel a été émis (mainnet, devnet ou validateur local) et la charge utile de réponse est capturée dans la transcription, non seulement paraphrasée
- Chaque transaction a été simulée (
simulateTransactionou équivalent) avant toute étape de signature/envoi ; les journaux de simulation sont joints - Pour toute transaction signée/envoyée, la signature résultante est enregistrée et confirmée en chaîne (statut renvoyé par
getSignatureStatusesou une URL explorateur) - Le slippage, les frais de priorité et les limites d'unités de calcul ont été définis explicitement avec des valeurs numériques concrètes, et non laissés aux défauts de la bibliothèque
- Les adresses de comptes, les mints et les ID de programmes utilisés dans l'exécution correspondent aux adresses coingecko-market-data documentées pour le cluster ciblé (pas de mélange mainnet/devnet)
- Le chemin d'échec a été exercé au moins une fois (solde insuffisant, oracle obsolète, blockhash expiré, etc.) et la gestion des erreurs de l'agent a produit un message lisible