Backend-for-Frontend (BFF) API for LendPilot - Lending market rates analytics
This API provides aggregated data from multiple sources (AaveKit GraphQL, The Graph Subgraph, Ethereum RPC) with caching, retry logic, and rate limiting. All endpoints return JSON responses unless otherwise specified.
Base URL: /api/v1
Rate Limits: 100 req/min (live data), 20 req/min (historical data)
Cache TTL: 30-60s (live), 6-24h (historical)
/marketsReturns list of all configured markets.
Response: {
"markets": [
{
"marketKey": "ethereum-v3",
"displayName": "Ethereum V3",
"poolAddress": "0x...",
"subgraphId": "...",
"chainId": 1
}
]
}/market/{marketKey}Returns current state of all assets in a market with totals.
Response: {
"reserves": [
{
"underlyingAsset": "0x...",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"imageUrl": "...",
"currentState": {
"supplyAPR": 0.05,
"borrowAPR": 0.08,
"totalSuppliedUSD": 1000000,
"totalBorrowedUSD": 500000,
"utilizationRate": 0.5
}
}
],
"totals": {
"totalSupply": 1000000000,
"supply": 500000000,
"borrowing": 500000000,
"assetCount": 60
}
}/market/{marketKey}/timeseries?window=30d|6m|1yReturns market totals time series data for the specified time window.
Response: {
"marketKey": "ethereum-v3",
"data": [
{
"date": "2025-01-01",
"timestamp": 1735689600,
"totalSuppliedUSD": 1000000000,
"totalBorrowedUSD": 500000000,
"availableLiquidityUSD": 500000000
}
],
"assetChanges": [...],
"totals": {...}
}/reserve/{marketKey}/{underlying}Returns current state and metadata for a specific asset.
/reserve/{marketKey}/{underlying}/snapshots/dailyReturns daily snapshots for the last 90 days.
/reserve/{marketKey}/{underlying}/snapshots/monthlyReturns monthly aggregated snapshots for the last 24 months.
/reserve/{marketKey}/{underlying}/snapshots/daily/csvReturns daily snapshots as CSV file. Format: comma separator, UTF-8 encoding, ISO dates (YYYY-MM-DD).
/reserve/{marketKey}/{underlying}/liquidity-impactReturns calculated liquidity impact scenarios for different transaction sizes.
/stablecoinsReturns aggregated stablecoin data across all markets.
Historical APR is calculated from liquidity and borrow indices using compound interest formula:
dailyGrowth = (indexEnd / indexStart)^(1/days) APR = (dailyGrowth - 1) * 365 Where: - indexStart: Index value at start of period - indexEnd: Index value at end of period - days: Number of days in period - Indices are stored as Ray (1e27) values
This formula provides accurate historical APR based on actual index growth, not current rates.
Market-level totals are calculated by aggregating all reserves:
Total Supply = Σ(totalSuppliedUSD for all reserves) Total Borrowing = Σ(totalBorrowedUSD for all reserves) Available Supply = Total Supply - Total Borrowing Where: - totalSuppliedUSD = (totalATokenSupply / 10^decimals) * priceUSD - totalBorrowedUSD = (totalCurrentVariableDebt / 10^decimals) * priceUSD - priceUSD = usdExchangeRate * 1e8 (converted from AaveKit format)
Utilization rate indicates how much of available liquidity is borrowed:
utilizationRate = borrowed / (borrowed + availableLiquidity) Where: - borrowed: Total current variable debt - availableLiquidity: Available liquidity for borrowing
All addresses are normalized to lowercase and validated as Ethereum addresses (0x + 40 hex characters).
All dates are in ISO format (YYYY-MM-DD). Timestamps are Unix seconds (number).
Large numbers (onchain values) are stored as strings to avoid precision loss. USD values are numbers with 2 decimal precision. APR values are numbers (0-1 range, e.g., 0.05 = 5%).
CSV files use comma separator, UTF-8 encoding, ISO date format (YYYY-MM-DD). USD values have 2 decimals, APR values have 4 decimals.
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": "Optional additional details"
}
}INVALID_MARKET - Invalid market keyINVALID_ADDRESS - Invalid asset addressMARKET_NOT_FOUND - Market not foundRESERVE_NOT_FOUND - Asset not found in marketUPSTREAM_ERROR - External API errorRATE_LIMIT_EXCEEDED - Too many requests (429)INTERNAL_ERROR - Server error (500)fetch('/api/v1/market/ethereum-v3')
.then(res => res.json())
.then(data => {
console.log('Total Supply:', data.totals.totalSupply);
console.log('Reserves:', data.reserves);
});const address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
fetch(`/api/v1/reserve/ethereum-v3/${address}/snapshots/daily`)
.then(res => res.json())
.then(snapshots => {
console.log('Daily snapshots:', snapshots);
});// Trigger CSV download window.location.href = '/api/v1/reserve/ethereum-v3/0x.../snapshots/daily/csv';