The unified earn listing
GET/v1/data/earn
Lending supply sides and vaults as ONE paginated row shape (EarnMarket), every rate in PERCENT (rateUnit: "percent"). Served from the origin's /earn/latest when it can answer, else from an edge merge of /pools/latest + /vaults/latest; the shape is identical either way and a failing source is reported in sources[].
Issuer fields on asset
asset.issuer{id,name,kind?}— whose INSTRUMENT the deposit token is.asset.issuerExposures[{id,name,kind?,hops}]— whose credit a wrapper leaves you holding; absent on a spot token.asset.desk— the credit desk (CreditDesk),nullwhen the token names no issuer (WETH).asset.denomination— the MONEY the token is worth, uppercase (USD,EUR,ETH,BTC, …):props.stablecoin.base, elseprops.savings.base, elseprops.lst.asset(an LST/LRT — wstETH, weETH, LBTC), elseprops.denomination(WETH →ETH, WBTC →BTC), else — for a PT or other wrapper, or a native token — its underlying's / wrapped twin's;nullwhen none.props.stablecoinis believed only when the token names an issuer (or exposure) or its asset group /chainId-addressis in token-lists' identity-keyed stablecoin snapshot (scripts/stablecoin/stablecoin.json): the lists also stamp it by bare ticker, which tags non-dollars asUSD. Notrisk.denomination, which isstable/volatile.
All four are stamped from the token map by chainId + address on BOTH serving paths. null means "resolved: none"; an absent field means the token map was unavailable for that chain.
A token's credit desk (see CreditDesk) is the token's own issuer, unless that issuer is a pure instrument wrapper (Pendle, Spectra, Exponent, or any token carrying a pendle/spectra/exponent/receipt prop) — then its fewest-hop non-instrument issuerExposures entry, with the instrument issuer as via. A PT-sUSDe is { id: 'ethena', via: 'pendle', hops: 1 } — Pendle's instrument, Ethena's credit; Strata's srUSDe is { id: 'strata', hops: 0 } — its own issuer's token, even though it is exposed to Ethena. An instrument issuer is never a desk.
Two things are deliberately NOT a desk:
- A loop's debt. A stablecoin you owe is not an exposure to its issuer: a USDC-funded sUSDe loop is Ethena credit, not Circle credit. Strategies group by their COLLATERAL's desk.
- A vault's
exposureblock. That is the curator's current allocation (one Fluid USDC vault spans eight collaterals and six desks), a DISCLOSURE about the position that moves on every rebalance. A vault row's desk is its deposit token's (asset.desk): a Steakhouse USDC vault is on Circle's desk.
issuers and issuerMatch
issuers=sky,ethena keeps rows whose deposit token answers to one of the ids under issuerMatch: any (default — own issuer or any exposure leg), direct, exposure, or credit (exactly asset.desk; the one mode under which issuers PARTITIONS the listing). On the origin path any/exposure ALSO match a vault through its allocation (exposure.legs). On the edge merge only the deposit token's desks are known, so the response then carries issuerScope: "deposit-token". credit is always answered by the edge merge (it filters the whole catalogue, then pages).
Asset class (asset.assetClass, asset.underlyingTicker)
asset.assetClass— WHAT KIND of real-world asset the deposit token is:stock·etf·pre-ipo·fund·credit·commodity, read verbatim off token-listsprops.rwa(type+subType: equity/stock →stock, equity/pre-ipo →pre-ipo, fund/etf →etf, other funds →fund, credit →credit, commodity →commodity). Never guessed from a ticker.null= not a tokenized real-world asset (crypto); absent = the token map was unavailable for that chain.asset.underlyingTicker— the real-world instrument a tokenized equity / ETF tracks, upper-cased (TSLAon TSLAx, TSLAon and Dinari's TSLA alike);nullon every other class.
assetClasses=stocks keeps rows whose deposit token is of one of the classes; aliases stocks = equity = stock + etf + pre-ipo, rwa = every class. underlyingTickers=TSLA,NVDA keeps rows whose asset.underlyingTicker is one of them. Both together AND. A token with no class never matches. Forwarded to the origin; an origin that does not apply them is detected on the page and the request is answered by the edge merge instead. An unknown class or a malformed ticker is a 400 naming the valid values.
Plain-text reference — GET /v1/data/earn
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
chainIds | query | string | yes | CSV of chain ids (alias chainId). See the ChainId schema for the full set of supported chains. |
issuers | query | string | no | CSV of issuer ids (alias issuer) — WHOSE CREDIT the deposit asset is, not the money it is worth and not the venue or curator hosting it. |
issuerMatch | query | any, direct, exposure, credit | no | Which desk issuers matches — see the description. credit = exactly asset.desk. |
assetClasses | query | string | no | CSV of asset classes — stock, etf, pre-ipo, fund, credit, commodity — or the aliases stocks / equity (stock + etf + pre-ipo) and rwa (all). Matches asset.assetClass; an unknown value is a 400. |
underlyingTickers | query | string | no | CSV of real-world tickers a tokenized equity / ETF tracks (asset.underlyingTicker, case-insensitive). ANDed with assetClasses. |
venueKind | query | lending, vault | no | lending or vault. |
assetGroup | query | string | no | Exact asset group of the deposit token. |
shareGroup | query | string | no | Exact asset group of the SHARE token a vault mints (shareToken.assetGroup): the vaults that leave you holding that token, e.g. Nest's savings vault for nOPAL. Vault rows only. |
assetSymbol | query | string | no | Exact symbol of the deposit token. |
denomination | query | string | no | Filters risk.denomination (stable / volatile) — NOT asset.denomination. |
q | query | string | no | Free-text search across names, brands, symbols and addresses. |
sort | query | rate, marketRate, tvl, liquidity | no | Sort key, descending. |
start | query | integer | no | Page offset. |
limit | query | integer | no | Page size, 1–1000 (alias count). |
terms | query | none, digest, full | no | Term-sheet depth on each row. A row whose floating yield IS perp funding (sUSDe, stUSR, wstUSR) also gets termSheet.hedge: the Pendle Boros fixed-rate lock for that funding (SHORT YU on Arbitrum), priced per unit of notional at a $10k reference — see TermFundingHedge. Never on a principal token or a fixed-maturity row. |
maxRiskScore | query | integer | no | Risk ceiling on risk.score (1–5; 6 = compromised — drained / insolvent / abandoned). Defaults to 5, so a 6 is only returned when set to 6 explicitly. A row with no score is kept. A market inherits the risk of its config: on a pooled or cross-margin lender every collateral in the config counts, so one high-risk collateral (e.g. an oracle that has not moved in a week) raises every market borrowable there. |
minTvlUsd | query | number | no | TVL floor in USD. 0 = no floor. An unpriced row (no TVL) is kept. |
minLiquidityUsd | query | number | no | Withdrawable-liquidity floor in USD. |
depositable | query | true | no | Only rows that accept deposits right now (availability.canDeposit). Off by default. |
passthrough | query | include | no | Include PASSTHROUGH rows, hidden by default: a market whose quoted rate is only the deposit token's own yield (an LST pool paying 0 % of its own). excluded.passthrough counts what the default hid. |
illiquid | query | include | no | Include rows flagged risk.illiquid, hidden by default. |
lp | query | include | no | Include rows whose position is a multi-token LP (the asset column names one leg only), hidden by default. |
includeExpired | query | true, false | no | Include matured fixed-maturity rows (e.g. an expired PT), hidden by default. |
protocol | query | string | no | CSV of protocol names or keys (protocol.name / protocol.key; alias protocols). |
venue | query | string | no | CSV of venues, matched on venue (alias venues). |
brand | query | string | no | CSV of brands, matched on brand (alias brands). |
curator | query | string | no | CSV of curator names, matched on curator.name (alias curators). |
yieldProfile | query | string | no | Exact risk.yieldProfile (e.g. yield-bearing, volatile). |
includeFixedTerm | query | true, false | no | Show FIXED-YIELD order-book / auction rows: Morpho Midnight, Term Finance, TermMax, Loopscale, Jupiter Offerbook. Hidden by default because they are not pools — the rate is the best executable quote for ONE maturity (on Midnight, the cheapest borrower ask), rate.kind is fixed-term, and the size is that book's depth. excluded.fixedTerm counts what the default hid. Midnight collateral legs are never listed (excluded.collateralLeg). |
Response 200
| Field | Type | Description |
|---|---|---|
success | True | |
data | object | Informational payload. null when the endpoint only builds calldata. |
actions | null |
Example response
{
"success": true,
"data": {}
}
Request
Responses
- 200
- 400
- 429
- 500
- 502
- 503
The earn envelope: items (EarnMarket rows, with asset.issuer / issuerExposures / desk / denomination / assetClass / underlyingTicker), total, sources, excluded, appliedDefaults, facets, and issuerScope when the issuer filter was answered over deposit-token desks only.
Validation error
Rate limited. Unauthenticated callers share a per-IP budget; send an x-api-key header to lift it. Retry with exponential backoff.
Unexpected server error. Safe to retry with backoff.
An upstream data source or protocol origin failed (error.code is ORIGIN_FAILED). error.details carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400.
FILTER_UNAVAILABLE — issuers (or assetClasses / underlyingTickers) was asked, the origin could not answer, and the token map for a requested chain could not be loaded, so the edge merge cannot answer either.