This guide covers every endpoint in the Earn Data API with full parameter documentation and response examples. The Earn Data API handles vault discovery, analytics, and portfolio tracking. For executing deposits and withdrawals, see the Composer API Integration Guide .
Base URL
All endpoints are prefixed with /v1/earn/.
The Earn Data API and Composer use different base URLs . Earn Data API endpoints use https://earn.li.fi, while Composer endpoints (e.g., GET /v1/quote) use https://li.quest. See the overview for details.
API Overview
Endpoint Description GET /v1/earn/vaultsList vaults with filtering and pagination GET /v1/earn/vaults/:chainId/:addressGet a single vault’s full details GET /v1/earn/chainsList chains with active vaults GET /v1/earn/protocolsList protocols with active vaults GET /v1/earn/portfolio/:userAddress/positionsGet a user’s DeFi positions
Authentication
The Earn Data API uses the same authentication as the rest of the LI.FI API. Pass your API key via the x-lifi-api-key header:
curl -X GET 'https://earn.li.fi/v1/earn/vaults' \
--header 'x-lifi-api-key: YOUR_API_KEY'
API keys are created via the LI.FI Partner Portal . See Authentication for full details.
Rate Limits
The default rate limit for Earn Data API endpoints is 50 requests per minute per API key.
If you need higher limits, contact our team via the LI.FI Partner Portal .
If you exceed the limit, you’ll receive a 429 Too Many Requests response. See Rate Limits for details on rate limit headers and best practices.
List Vaults
Returns a paginated list of vaults with optional filtering and sorting.
Query Parameters
Parameter Type Required Default Description chainIdintegerNo — Filter by EVM chain ID (e.g., 8453 for Base, 1 for Ethereum) assetstringNo — Filter by underlying token symbol (e.g., "USDC", "ETH") protocolstringNo — Filter by protocol name (e.g., "morpho-v1", "aave-v3") minTvlUsdnumberNo — Minimum TVL in USD (e.g., 1000000 for $1M+) sortBystringNo — Sort order: "apy" (highest first) or "tvl" (highest first) limitintegerNo 50Results per page (1–100) cursorstringNo — Pagination cursor from a previous response’s nextCursor
Example Request
curl -X GET 'https://earn.li.fi/v1/earn/vaults?\
chainId=8453&\
asset=USDC&\
sortBy=apy&\
minTvlUsd=100000&\
limit=10'
Response
{
"data" : [
{
"address" : "0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A" ,
"network" : "base" ,
"chainId" : 8453 ,
"slug" : "morpho-base-usdc-0x7bfa" ,
"name" : "Morpho USDC Vault" ,
"description" : "Optimized USDC lending vault on Morpho" ,
"protocol" : {
"name" : "Morpho" ,
"logoUri" : "https://example.com/morpho-logo.png" ,
"url" : "https://morpho.org"
},
"underlyingTokens" : [
{
"address" : "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" ,
"symbol" : "USDC" ,
"decimals" : 6 ,
"weight" : 1.0
}
],
"lpTokens" : [
{
"address" : "0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A" ,
"symbol" : "mUSDC" ,
"decimals" : 18 ,
"priceUsd" : "1.02"
}
],
"rewardTokens" : [],
"tags" : [ "stablecoin" , "lending" ],
"analytics" : {
"apy" : {
"base" : 0.0534 ,
"reward" : null ,
"total" : 0.0534
},
"apy1d" : 0.0521 ,
"apy7d" : 0.0538 ,
"apy30d" : 0.0545 ,
"tvl" : {
"usd" : "12500000.00" ,
"native" : "12500000000000"
},
"updatedAt" : "2026-03-31T14:30:00.000Z"
},
"caps" : {
"totalCap" : "50000000000000" ,
"maxCap" : "100000000000000"
},
"timeLock" : 0 ,
"kyc" : false ,
"isTransactional" : true ,
"isRedeemable" : true ,
"depositPacks" : [
{ "name" : "morpho-deposit" , "stepsType" : "instant" }
],
"redeemPacks" : [
{ "name" : "morpho-redeem" , "stepsType" : "instant" }
],
"syncedAt" : "2026-03-31T14:30:00.000Z"
}
],
"nextCursor" : "eyJpZCI6MTAwfQ" ,
"total" : 47
}
Some fields may be null in the response: description (absent for ~70% of vaults), apy.base, apy.reward, apy1d, apy7d, and caps. Always handle nullable fields in your integration.
The API uses cursor-based pagination. To fetch the next page, pass the nextCursor value from the response as the cursor query parameter:
// Fetch all vaults across pages
let cursor : string | undefined ;
const allVaults = [];
do {
const params = new URLSearchParams ({ limit: '100' });
if ( cursor ) params . set ( 'cursor' , cursor );
const response = await fetch ( `https://earn.li.fi/v1/earn/vaults? ${ params } ` );
const { data , nextCursor } = await response . json ();
allVaults . push ( ... data );
cursor = nextCursor ;
} while ( cursor );
Get Vault by Chain and Address
GET /v1/earn/vaults/:chainId/:address
Returns the full details for a single vault.
Path Parameters
Parameter Type Required Description chainIdintegerYes EVM chain ID addressstringYes Vault contract address (0x-prefixed, 40 hex characters)
Example Request
curl -X GET 'https://earn.li.fi/v1/earn/vaults/8453/0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A'
Response
Returns a single NormalizedVault object (same shape as items in the list endpoint).
Errors
Status Description 400Invalid chain ID or address format 404Vault not found
List Supported Chains
Returns the list of chains that have at least one vault available. Derived from current vault data.
Example Request
curl -X GET 'https://earn.li.fi/v1/earn/chains'
Response
[
{
"name" : "Ethereum" ,
"chainId" : 1 ,
"networkCaip" : "eip155:1"
},
{
"name" : "Base" ,
"chainId" : 8453 ,
"networkCaip" : "eip155:8453"
},
{
"name" : "Arbitrum One" ,
"chainId" : 42161 ,
"networkCaip" : "eip155:42161"
}
]
List Supported Protocols
Returns the list of protocols that have at least one vault available. Derived from current vault data.
Example Request
curl -X GET 'https://earn.li.fi/v1/earn/protocols'
Response
[
{
"name" : "Morpho" ,
"logoUri" : "https://example.com/morpho-logo.png" ,
"url" : "https://morpho.org"
},
{
"name" : "Aave V3" ,
"logoUri" : "https://example.com/aave-logo.png" ,
"url" : "https://aave.com"
},
{
"name" : "Euler" ,
"logoUri" : "https://example.com/euler-logo.png" ,
"url" : "https://www.euler.finance"
}
]
Get User Portfolio Positions
GET /v1/earn/portfolio/:userAddress/positions
Returns a user’s DeFi positions across all supported protocols.
Path Parameters
Parameter Type Required Description userAddressstringYes User’s wallet address (0x-prefixed, 40 hex characters)
Example Request
curl -X GET 'https://earn.li.fi/v1/earn/portfolio/0x1234567890abcdef1234567890abcdef12345678/positions'
Response
{
"positions" : [
{
"chainId" : 1 ,
"protocolName" : "aave-v3" ,
"asset" : {
"address" : "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" ,
"name" : "USD Coin" ,
"symbol" : "USDC" ,
"decimals" : 6
},
"balanceUsd" : "1523.45" ,
"balanceNative" : "1523450000"
},
{
"chainId" : 8453 ,
"protocolName" : "morpho" ,
"asset" : {
"address" : "0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A" ,
"name" : "Morpho USDC Vault" ,
"symbol" : "mUSDC" ,
"decimals" : 18
},
"balanceUsd" : "5000.00" ,
"balanceNative" : "4901960784313725490196"
}
]
}
Errors
Status Description 400Invalid wallet address format
Error Handling
All Earn Data API endpoints return standard HTTP error responses:
Status Meaning 200Success 400Bad request. Invalid parameters (check the error message for details). 404Resource not found (vault does not exist) 500Internal server error
Error responses include a message describing the issue:
{
"statusCode" : 400 ,
"message" : "Invalid Ethereum address"
}
Next Steps
Discover and Deposit Recipe End-to-end recipe combining Earn discovery with Composer deposits
Composer API Guide Execute deposits and withdrawals via the Composer API