Coin Data Integration
Add external blockchain/token data API integrations in lib/coin-data/.
When to Use
- Integrating a new token data API (price feeds, market data, holder info)
- Adding a new data source for coin enrichment
- Building chain-specific data fetchers
Procedure
- Create a new file in
lib/coin-data/ (e.g., birdeye.ts)
- Define response types/interfaces
- Implement fetch functions with error handling and caching
- Add chain mapping if the API uses different chain identifiers
- Export functions for use in server actions or API routes
Template
// lib/coin-data/my-api.ts
const MY_API_BASE = "https://api.example.com/v1"
// Response types
interface MyApiTokenData {
address: string
symbol: string
name: string
priceUsd: number
marketCap: number
volume24h: number
holders: number
}
// Chain identifier mapping (APIs use different chain names)
const CHAIN_MAP: Record<string, string> = {
solana: "solana",
base: "base",
bnb: "bsc",
ethereum: "ethereum",
}
// Main fetch function
export async function getTokenData(
chain: string,
contractAddress: string,
): Promise<MyApiTokenData | null> {
const apiChain = CHAIN_MAP[chain]
if (!apiChain) return null
try {
const headers: Record<string, string> = {
accept: "application/json",
}
// Optional API key from env
const apiKey = process.env.MY_API_KEY
if (apiKey) headers["X-API-Key"] = apiKey
const res = await fetch(
`${MY_API_BASE}/tokens/${apiChain}/${contractAddress}`,
{
headers,
next: { revalidate: 60 }, // ISR cache: 60 seconds
},
)
if (!res.ok) return null
return await res.json()
} catch (error) {
console.error("MyAPI fetch failed:", error)
return null // Graceful degradation — never throw
}
}
// URL builder for embeds/links
export function getMyApiUrl(chain: string, contractAddress: string): string {
const apiChain = CHAIN_MAP[chain] || "solana"
return `https://example.com/${apiChain}/${contractAddress}`
}
Rules
- File location:
lib/coin-data/<api-name>.ts
- Never throw — return
null or [] on failure (graceful degradation)
- Log errors with
console.error("ApiName fetch failed:", error)
- Cache responses with
next: { revalidate: N } in fetch options
- API keys from
process.env — add optional header if key exists
- Chain mapping — always map internal chain names (
solana, base, bnb, ethereum) to API-specific identifiers
- Type responses — define interfaces for API response data
- Supported chains: solana, base, bnb, ethereum (from
lib/constants.ts)
- Existing integrations to reference:
dexscreener.ts, coingecko.ts, pumpfun.ts
1---2name: coin-integration3description: Add new external coin/token data API integrations. Use when: integrating DexScreener, PumpFun, CoinGecko, or any new blockchain data API. Covers fetch patterns, response types, caching, error handling, and chain mapping.4---56# Coin Data Integration78Add external blockchain/token data API integrations in `lib/coin-data/`.910## When to Use1112- Integrating a new token data API (price feeds, market data, holder info)13- Adding a new data source for coin enrichment14- Building chain-specific data fetchers1516## Procedure17181. Create a new file in `lib/coin-data/` (e.g., `birdeye.ts`)192. Define response types/interfaces203. Implement fetch functions with error handling and caching214. Add chain mapping if the API uses different chain identifiers225. Export functions for use in server actions or API routes2324## Template2526```ts27// lib/coin-data/my-api.ts2829const MY_API_BASE = "https://api.example.com/v1"3031// Response types32interface MyApiTokenData {33 address: string34 symbol: string35 name: string36 priceUsd: number37 marketCap: number38 volume24h: number39 holders: number40}4142// Chain identifier mapping (APIs use different chain names)43const CHAIN_MAP: Record<string, string> = {44 solana: "solana",45 base: "base",46 bnb: "bsc",47 ethereum: "ethereum",48}4950// Main fetch function51export async function getTokenData(52 chain: string,53 contractAddress: string,54): Promise<MyApiTokenData | null> {55 const apiChain = CHAIN_MAP[chain]56 if (!apiChain) return null5758 try {59 const headers: Record<string, string> = {60 accept: "application/json",61 }6263 // Optional API key from env64 const apiKey = process.env.MY_API_KEY65 if (apiKey) headers["X-API-Key"] = apiKey6667 const res = await fetch(68 `${MY_API_BASE}/tokens/${apiChain}/${contractAddress}`,69 {70 headers,71 next: { revalidate: 60 }, // ISR cache: 60 seconds72 },73 )7475 if (!res.ok) return null76 return await res.json()77 } catch (error) {78 console.error("MyAPI fetch failed:", error)79 return null // Graceful degradation — never throw80 }81}8283// URL builder for embeds/links84export function getMyApiUrl(chain: string, contractAddress: string): string {85 const apiChain = CHAIN_MAP[chain] || "solana"86 return `https://example.com/${apiChain}/${contractAddress}`87}88```8990## Rules9192- **File location**: `lib/coin-data/<api-name>.ts`93- **Never throw** — return `null` or `[]` on failure (graceful degradation)94- **Log errors** with `console.error("ApiName fetch failed:", error)`95- **Cache responses** with `next: { revalidate: N }` in fetch options96- **API keys** from `process.env` — add optional header if key exists97- **Chain mapping** — always map internal chain names (`solana`, `base`, `bnb`, `ethereum`) to API-specific identifiers98- **Type responses** — define interfaces for API response data99- **Supported chains**: solana, base, bnb, ethereum (from `lib/constants.ts`)100- **Existing integrations** to reference: `dexscreener.ts`, `coingecko.ts`, `pumpfun.ts`