Get latest lending data (paginated by lender)
GET/v1/data/lending/latest
Returns latest per-market lending data for the requested chains, scoped to a specific page of lender keys.
Pagination
Both chains and lenders are required. A maximum of 20 lender keys may be supplied per request. Use GET /v1/data/lending/lenders to enumerate available lender keys (sorted by TVL) and page through them in batches of up to 20:
GET /v1/data/lending/lenders?chains=1,8453 → enumerate keys
GET /v1/data/lending/latest?chains=1,8453&lenders=k1,…,k20 → page 1
GET /v1/data/lending/latest?chains=1,8453&lenders=k21,…,k40 → page 2
Breaking changes vs previous /lending/latest
lendersis now required.- Hard cap of 20 lender keys per request.
- Top-level
lenderKeyfield is removed from items — uselenderInfo.key.
Lista DAO fixed-term (brokered) markets: a market is brokered when its terms[] rate card is non-empty and flags.variableBorrowDisabled === true. Such markets report variableBorrowRate = 0 but cannot be borrowed variably through 1delta — read terms[] for the available fixed terms and their APRs, and broker for the gateway contract. See the MarketTerm schema.
Morpho Midnight order-book markets (MORPHO_MIDNIGHT_<id>): liquidity is an order book of maker offers, not a pool. Pass includeOffers=true to attach the live two-sided ladder to each such market's loan leg: offers (bids — the demand a borrower TAKES) and lendOffers (asks — the supply a lender TAKES), both best-first with per-level aprPct, assets, assetsUsd, and cumulativeAssets. Plain pool markets return no offers (their single rate suffices). This is the read side of TAKE; to fill offers use the standard deposit/borrow actions, and to MAKE your own offer see /v1/actions/midnight/make.
Teller markets (TELLER_<pool>): fixed-term, fixed-APR pool loans with TIME-based liquidation — collateral is seized only on a missed payment past the market window, never on a price move (no margin calls). fixedTerm.model = "teller", provider.kind = "pool", rolling duration up to teller.maxLoanDuration. ⚠ AGGRESSIVE default terms — surface these prominently: on default the borrower can lose their ENTIRE escrowed collateral (a liquidator seizes all of it, not just the amount owed — at a 50% LTV that's ~2× the borrowed value), and the grace window after the term can be very short (params.market.teller.paymentDefaultDuration, observed as low as 300 s / 5 min). There is also an upfront origination fee (teller.originationFeePercent = marketFeeBps + protocolFeeBps, also on fixedTerm.fees.originationFeePercent). The market descriptor (params.market.teller) carries the read-side facts the UI should surface: implications (a ready-to-display string list — lead with the full-collateral-liquidation warning), paymentDefaultDuration, originationFeePercent, requiresBorrowerAttestation (this market only lets whitelisted borrowers open loans — a non-attested account is rejected at borrow time, so gate the borrow CTA on this flag), and marketOpen (a closed market reports borrowingEnabled = false). Borrowing is one atomic POST /v1/actions/lending/deposit-and-borrow; closing is a FULL POST /v1/actions/lending/withdraw-and-repay (repays everything and releases all collateral — Teller has no partial collateral withdrawal; posId = the bidId to close). Borrower positions are bidId-keyed sub-accounts.
Term Finance markets (TERM_FINANCE_<termRepoId>): fixed-rate, fixed-maturity tri-party repo. One repo per maturity, so a pair has many lender keys that differ only by date — read lenderInfo.name (e.g. "Term USDC / wstETH — 2026-09-03") rather than the raw key. fixedTerm.model = "term", provider.kind = "auction", flags.variableBorrowDisabled = true (there is no variable rate — a variableBorrowRate of 0 is NOT a free borrow).
⚠ Borrowing is only possible inside a scheduled sealed-bid auction round, and most repos are between rounds at any given time (live Ethereum book: typically ~3 of ~84). fixedTerm.auction carries the window and is the gate:
canBorrow— gate the borrow CTA on this, NOT onstatusor on the presence of a rate. It is true only while a round is accepting submissions.canLend— deliberately independent ofcanBorrow: lending also works between rounds by buying repo tokens on the secondary market, so a closed round leaves the market lend-only, not inert. Do not grey out the whole market.status—upcoming|open|revealing(bidding shut, prices revealing) |closed(no round listed).secondsUntilClose,startTime,revealTime(the deadline to act),endTime— unix seconds; derive a live countdown fromrevealTimerather than trustingsecondsUntilCloseagainst a cached response.minBorrowAmount/minLendAmount— a real per-round floor in loan-token base units (e.g. 1000 USDC). A smaller amount cannot be submitted at all, so validate before building.implications— ready-to-display string list, most important first (same convention asparams.market.teller.implications).
terms[] is emitted ONLY while canBorrow is true, so an empty rate card on a Term market means "not borrowable right now", not "no offers". When a round is open on a repo that has never cleared, terms[] is legitimately empty and variableBorrowRate is 0: the rate is whatever you bid, set at clearing. Any rate shown outside an open round is the previous round's clearing rate — historical, not obtainable (it still prices the secondary lend book, which is why it is reported at all).
Term sheets (termSheet): every market carries a structured description of its lend and borrow offer under one shape, for every lender we serve — pool lenders, fixed-term lenders, CDPs and vaults alike. termSheet.supply and termSheet.borrow each answer rate, maturity, fees, exit terms, liquidation, counterparty and availability; termSheet.governance, .oracle, .utilization and .constraints describe the market as a whole. Absence of a side is meaningful: no borrow means the market cannot be borrowed.
Read info.headline and info.tags for a ready-to-render summary, and info.implications[] (ordered most-important-first) for the consequences that a rate alone hides — a Teller borrow can lose its ENTIRE collateral after a grace window as short as 300 s, a TermMax lender can be settled in collateral instead of the asset they lent, and a Liquity trove can be redeemed at par while perfectly healthy. coverage distinguishes "does not apply here" (notApplicable, e.g. Teller genuinely has no oracle) from "not classified yet" (pending) — a missing block is never a claim of absence.
Every string field is an OPEN enum: new members are added additively and MUST NOT break a client. Give every switch a default branch and fall back to info.headline, which is always populated.
Oracle risk: each market carries an oracleInfo object classifying its price oracle's feed correctness (provider, reported vs intended pair, a 0–100 worstScore/worstBand, and flags such as wrong-asset/correlated-proxy/cross-numeraire). This is distinct from the price-staleness signal in risk.breakdown[oracle]. See the OracleInfo schema for the full scoring model.
Plain-text reference — GET /v1/data/lending/latest
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
chains | query | string[] | yes | Chain IDs to query (repeatable, CSV also accepted) |
lenders | query | string[] | yes | Lender keys to fetch (repeatable, CSV also accepted). Max 20 per request. See the LenderId schema for the full set of accepted values. |
maxRiskScore | query | integer | no | Max risk score (1–5). Defaults to 4. |
terms | query | digest, full, none | no | Term-sheet depth attached to every market as termSheet. digest (default) is the compact form — headline, tags, rate/maturity/exit/liquidation summary and the exposure ROLLUP, but no items[] and no long prose. full inlines the complete sheet including backedBy.items[] / acceptedCollateral.items[] and info.description + info.implications[]. none omits the field entirely. Every exposure item carries its own marketUid, so digest is not a dead end — resolve the ones you need in one call. |
includeOffers | query | boolean | no | Order-book markets (Morpho Midnight) only. When true, attach the live maker-offer ladder to each order-book market’s loan leg (offers = bids, lendOffers = asks). Ignored for pool markets. Defaults to false. |
Response 200
| Field | Type | Description |
|---|---|---|
success | True | |
data | object | Latest lending market data as a flat list of lender/chain entries. Returns only the lender keys requested via lenders=… (max 20 per request). |
data.count | integer | Number of lender/chain entries |
data.items | object[] | Flat array of lender/chain entries |
data.items[].chainId | string | EVM chain id, as a decimal string. See the ChainId schema. |
data.items[].lenderInfo | object | Protocol/lender metadata (name, logo). |
data.items[].lenderInfo.key | string | Lender key identifier |
data.items[].lenderInfo.name | string | Human-readable lender name |
data.items[].lenderInfo.logoURI | string | Lender logo URL |
data.items[].lastFetched | number | Epoch ms of latest snapshot |
data.items[].totalDepositsUsd | number | Total deposits across all markets in USD |
data.items[].totalDebtUsd | number | Total debt across all markets in USD |
data.items[].tvlUsd | number | Total value locked in USD (deposits - debt) |
data.items[].params | object | Lender-specific parameters. Only present for Morpho/Lista lenders (e.g. { market: { … } }). |
data.items[].fixedTerm | object | Fixed-term descriptor for this lender key. Absent/null on variable-rate lenders. For Term Finance read fixedTerm.auction.canBorrow before offering a borrow — most repos sit between auction rounds and cannot be borrowed even though they quote a rate. |
data.items[].markets | object[] | Individual lending markets for this lender on this chain |
data.items[].markets[].lenderKey | string | Protocol identifier |
data.items[].markets[].poolId | string | Pool/vault address or protocol-specific ID |
data.items[].markets[].depositRate | number | Deposit APR (percent) |
data.items[].markets[].variableBorrowRate | number | Variable borrow APR (percent) |
data.items[].markets[].stableBorrowRate | number | Stable borrow APR (percent) |
data.items[].markets[].intrinsicYield | number | Intrinsic yield APR from underlying asset (e.g. stETH staking) |
data.items[].markets[].totalDeposits | number | Total deposits in token units |
data.items[].markets[].totalDebtStable | number | Total stable debt in token units |
data.items[].markets[].totalDebt | number | Total variable debt in token units |
data.items[].markets[].totalLiquidity | number | Available liquidity (totalDeposits - totalDebt) in token units |
data.items[].markets[].totalDepositsUsd | number | Total deposits in USD |
data.items[].markets[].totalDebtStableUsd | number | Total stable debt in USD |
data.items[].markets[].totalDebtUsd | number | Total variable debt in USD |
data.items[].markets[].totalLiquidityUsd | number | Available liquidity in USD |
data.items[].markets[].utilization | number | Utilization ratio (totalDebt / totalDeposits) |
data.items[].markets[].decimals | integer | Token decimals — divide raw amounts by 10 ** decimals. |
data.items[].markets[].underlyingInfo | object | Nested asset metadata, oracle prices, and market prices for a lending market. |
data.items[].markets[].oracleInfo | object | Oracle feed-correctness classification for the market's price oracle(s). null when the market has no oracle classification. This is feed correctness — does the oracle price the right asset in the right unit — and is distinct from the price-staleness signal carried in risk.breakdown[oracle] (a 1–5 score). A market can have several feeds (Compound comets price each collateral asset; Fluid prices each vault side), so feeds is an array and worstScore/worstBand summarize the riskiest one. Scoring (per feed, additive): score = provider base + flag penalties, clamped 0–100. Provider base (oracle mechanism; first match wins): | Provider | Base | |---|---| | chainlink, price-cap | 10 | | redstone/pyth/chronicle/… and unrecognized | 18 | | composite / cross-feed | 22 | | exchange-rate / pendle-pt / LST rate adapters | 28 | | twap/uniswap/DEX | 30 | | fixed-rate / constant | 55 | Flag penalties (added on top): wrong-asset +45 · correlated-proxy +18 · cross-numeraire +18 · undecoded-source +8. Bands: LOW < 25 · MEDIUM 25–49 · HIGH 50–74 · CRITICAL ≥ 75. |
data.items[].markets[].caps | object | Supply, borrow, and debt ceiling caps for a lending market. |
data.items[].markets[].flags | object | Boolean flags describing the operational status of a lending market. Values may be null if unavailable from the protocol. |
data.items[].markets[].rewards | object[] | Active reward programs. Defaults to [] when none. |
data.items[].markets[].config | object | Risk config keyed by mode/category ID (e.g. "0" for default, "1" for e-mode) |
data.items[].markets[].terms | object[] | Fixed-term rate card for Lista DAO brokered markets. Non-empty ⇒ the market is brokered (borrow via the broker, pick a termId); null ⇒ a regular variable-rate market. Together with flags.variableBorrowDisabled this is the canonical brokered-market signal. |
data.items[].markets[].broker | string | Lista DAO LendingBroker contract address — the mandatory gateway for the debt side (borrow/repay) of a brokered market. Present (non-zero) only for brokered markets. The borrow/repay calldata routes through this contract (the SDK and worker resolve it automatically). |
Request
Responses
- 200
- 400
- 429
- 500
- 502
Latest lending data
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.