Token Terminal API Integration
Token Terminal aggregates financial metrics of DeFi protocols using model familiar from traditional finance: revenue, P/E ratio, price-to-sales, TVL, active users. Data source — on-chain events and The Graph subgraphs, normalized into single schema. API provides historical data and current snapshots across 100+ protocols.
Integration needed in two typical scenarios: research dashboard comparing protocols and investment tool with valuation metrics.
API structure and key endpoints
Token Terminal provides REST API with key (API key in header Authorization: Bearer <key>).
Main endpoints:
GET /v2/projects — list of all protocols
GET /v2/projects/{project_id} — metrics of one protocol
GET /v2/projects/{project_id}/timeseries — historical data
GET /v2/categories — aggregates by categories (DEX, lending etc.)
Key fields in project response:
| Field | Description |
|---|---|
revenue |
Annualized protocol revenue (not to be confused with trading volume) |
fees |
Gross fees (revenue + LP rewards) |
tvl |
Total Value Locked |
ps |
Price-to-Sales ratio |
pe |
Price-to-Earnings ratio |
dau |
Daily active users (on-chain) |
market_cap_circulating |
Market cap on circulating supply |
Important distinction: Token Terminal uses protocol revenue (share going to protocol, not LP) as analogue of net income. For Uniswap without activated fee switch revenue = 0, all fees go to LP. This makes Uniswap P/E infinite by their methodology.
Example request and data handling
const BASE_URL = 'https://api.tokenterminal.com/v2'
async function getProtocolMetrics(projectId: string) {
const response = await fetch(`${BASE_URL}/projects/${projectId}`, {
headers: {
'Authorization': `Bearer ${process.env.TOKEN_TERMINAL_API_KEY}`
}
})
if (!response.ok) throw new Error(`API error: ${response.status}`)
const data = await response.json()
return {
revenue30d: data.data.revenue_30d,
fees30d: data.data.fees_30d,
tvl: data.data.tvl,
ps: data.data.ps,
pe: data.data.pe
}
}
// Historical data for chart
async function getTimeseries(projectId: string, metric: string, days: number) {
const params = new URLSearchParams({
metric,
granularity: 'daily',
from: new Date(Date.now() - days * 86400000).toISOString()
})
const response = await fetch(
`${BASE_URL}/projects/${projectId}/timeseries?${params}`,
{ headers: { 'Authorization': `Bearer ${process.env.TOKEN_TERMINAL_API_KEY}` } }
)
return response.json()
}
Rate limits and caching
Free tier: 100 requests/day. Paid plans: from 10,000 to unlimited. For dashboard with multiple users must cache responses on server — requests from different clients to same data shouldn't multiply API calls.
Recommended caching scheme: Redis with TTL 15 minutes for current metrics, 24 hours for historical data from past days (won't change). On limit exceeded — exponential backoff, not retry loop.
Integration takes 1 day: API connection, cache layer, TypeScript types from response schema.







