Collateral ⇄ debt optimizer
GET/v1/data/lending/pairs/optimize
Filter pairs by either or both sides, then optionally compute the opposite-side amount per row.
Asset selection
collaterals / debts are reinterpreted by chain mode:
- Single chain (
chainId): values are token addresses. - Multi-chain or no chain: values are asset groups.
Use collateralGroups / debtGroups to force group semantics in any chain mode.
Group params and address params on the same side are OR'd.
The native asset, and why you usually want groups
The native asset is spelled as the zero address in every 1delta data payload. 0xEeee…EEeE is an encoding-layer sentinel — it is accepted on action inputs and normalised away, but it is never served here and never matches an address filter, so a client filtering by it silently gets zero rows.
Native and wrapped-native markets are different rows (0x0 on Fluid’s ETH vaults, 0xc02a… on Aave WETH) but share one assetGroup (ETH). Selecting by group therefore returns both — which is what you want whenever the two are interchangeable for your purpose (a migrate bridges them by wrapping, a leverage loop can open on either). It also removes any need for a per-chain wrapped-native address table in the client. Each asset also carries props.isNative + props.wrapped (native rows) and props.wnative (wrapped rows) if you need to tell them apart after the fact.
Amount params
The collateral and debt sides are independent — supply an amount on either side, both, or neither:
collateralAmount(token units; requires exactly one collateral asset)collateralAmountUsd(USD; multi-asset OK)debtAmount(token units; requires exactly one debt asset)debtAmountUsd(USD; multi-asset OK)
A collateral input adds maxDebtAmount + maxDebtAmountUsd to each row; a debt input adds minCollateralAmount + minCollateralAmountUsd. Supplying both a collateral and a debt amount returns both column pairs. Within a single side the token-unit and *Usd forms are mutually exclusive (400 otherwise).
Un-openable pairs are dropped by default on BOTH legs (includeIlliquid=true keeps them). Unconditionally: a collateral leg with no remaining supply capacity (depositableLong <= 0 — a full or deliberately zeroed supply cap, where the market returns 0 for a max-deposit query). Additionally, when an amount is supplied: a debt leg whose borrow liquidity cannot fund the resulting debt, and a collateral leg whose capacity cannot absorb the required collateral. With no amount supplied, a small-but-real capacity is a real (smaller) opportunity and stays listed; depositableLong: null means uncapped and always passes.
Depth-aware APR
Whenever an amount is supplied, each row also carries the EFFECTIVE APR at the computed notional: borrowAprAtAmount, depositAprAtAmount, netAprAtAmount. Each is the headline effective rate (depositAprLong / borrowAprShort, which fold in intrinsic yield + rewards) with only its ORGANIC (IRM) component re-priced at the utilization the position moves the pool to — intrinsic + rewards are size-invariant. So a curve lender that borrows near 0% at 0 notional prices materially higher at a real size, and netAprAtAmount is comparable to aprTotal but at the position's actual size/leverage. Pass depth=true to additionally receive the raw borrowDepthShort/supplyDepthLong grids.
Plain-text reference — GET /v1/data/lending/pairs/optimize
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
chainId | query | string | no | Single chain ID. When set, asset filters operate on token addresses. See the ChainId schema for the full set of supported chains. |
chainIds | query | string | no | CSV of chain IDs. When two or more, asset filters operate on asset groups. See the ChainId schema for the full set of supported chains. |
lender | query | string | no | Single lender key See the LenderId schema for the full set of accepted values. |
lenders | query | string | no | CSV of lender keys (prefix-expanded) See the LenderId schema for the full set of accepted values. |
excludeLenders | query | string | no | CSV of lender keys to exclude (prefix-expanded) |
collaterals | query | string | no | CSV of long-side filters. Token addresses (single chain) or asset groups (multi/no chain). |
debts | query | string | no | CSV of short-side filters. Same dual semantics as collaterals. |
collateralGroups | query | string | no | CSV of long-side asset groups (works in any chain mode). |
debtGroups | query | string | no | CSV of short-side asset groups (works in any chain mode). |
collateralTags | query | string | no | CSV of property flags the collateral (long) asset must carry, e.g. eth, btc, native, wnative, stablecoin, savings, lst, lrt, pendle, rwa. AND-ed with any collaterals/collateralGroups selection (narrows). Denomination flags (eth/btc) cover canonical base tokens only, not LST/derivative wrappers. |
collateralTagsMode | query | any, all | no | How to match multiple collateralTags: any (has at least one) or all (has every one). |
debtTags | query | string | no | CSV of property flags the debt (short) asset must carry (e.g. eth, btc, native, wnative, stablecoin, savings, lst, lrt, pendle, rwa). Same semantics as collateralTags. Example: collateralTags=lst&debtTags=wnative for leveraged staking. |
debtTagsMode | query | any, all | no | How to match multiple debtTags: any or all. |
includeExpired | query | boolean | no | Include pairs whose collateral or debt is an expired Pendle PT. Excluded by default (judged live off props.pendle.expiry/expired). |
collateralAmount | query | number | no | Token-unit collateral amount. Requires exactly one collateral asset. |
collateralAmountUsd | query | number | no | USD collateral amount. Multi-asset selections OK. |
debtAmount | query | number | no | Token-unit debt amount. Requires exactly one debt asset. |
debtAmountUsd | query | number | no | USD debt amount. Multi-asset selections OK. |
depth | query | boolean | no | When true, also return the raw borrowDepthShort/supplyDepthLong rate-at-depth grids. The *AtAmount depth-aware scalars are returned whenever an amount is supplied, regardless of this flag. |
includeIlliquid | query | boolean | no | By default the optimizer drops collateral legs with no remaining supply capacity, and — when an amount is supplied — pairs whose borrow liquidity cannot fund the resulting debt or whose collateral capacity cannot absorb the required collateral. Set true to keep such (un-openable) pairs. |
minApr | query | number | no | Minimum total APR |
maxApr | query | number | no | Maximum total APR |
minLeverage | query | number | no | Minimum leverage |
minDepositApr | query | number | no | Min deposit APR including intrinsic yield (long side) |
maxBorrowRate | query | number | no | Max borrow rate including intrinsic yield (short side) |
minLtv | query | number | no | Minimum LTV (0-1) |
maxUtilizationLong | query | number | no | Max collateral-side utilization (0-1) |
maxUtilizationShort | query | number | no | Max debt-side utilization (0-1) |
minLiquidityUsdLong | query | number | no | Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — capacity is gated separately (see includeIlliquid). |
minBorrowLiquidityUsd | query | number | no | Min debt-side borrow liquidity USD |
minDepositsUsdLong | query | number | no | Min collateral-side deposits USD |
minDebtUsdShort | query | number | no | Min debt-side total debt USD |
maxRiskScore | query | number | no | Backwards-compat alias for maxConfigRiskScore |
maxConfigRiskScore | query | number | no | Max config risk score |
maxTokenRiskScore | query | number | no | Max token risk score |
maxChainRiskScore | query | number | no | Max chain risk score |
maxLenderRiskScore | query | number | no | Max lender risk score |
start | query | integer | no | Pagination offset |
count | query | integer | no | Page size (max 100) |
sortBy | query | aprTotal, aprBase, maxLeverage, ltv, depositAprLong, borrowAprShort, … (15 values) | no | Sort field |
sortDir | query | ASC, DESC | no | Sort direction |
Response 200
| Field | Type | Description |
|---|---|---|
success | True | |
data | object | |
data.chainIds | string[] | EVM chain ids, as decimal strings. See the ChainId schema. |
data.collaterals | string[] | |
data.debts | string[] | |
data.collateralAmount | number | |
data.collateralAmountUsd | number | |
data.debtAmount | number | |
data.debtAmountUsd | number | |
data.start | integer | |
data.count | integer | Number of entries in items. |
data.items | object[] | The result set for this response. |
data.items[].chainId | string | EVM chain id, as a decimal string. See the ChainId schema. |
data.items[].lender | string | Protocol identifier. See the LenderId schema. |
data.items[].fixedTerm | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. For Term Finance (model: "term"), gate the borrow/loop CTA on fixedTerm.auction.canBorrow: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that aprBase/aprTotal on such a pair are computed against a variableBorrowRate of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever canBorrow is false. |
data.items[].marketLongUid | string | Market UID of the collateral side |
data.items[].marketShortUid | string | Market UID of the debt side |
data.items[].marketNameLong | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. |
data.items[].marketNameShort | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. |
data.items[].curatorNameLong | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. |
data.items[].curatorNameShort | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |
data.items[].assetLong | string | |
data.items[].assetShort | string | |
data.items[].assetGroupLong | string | |
data.items[].assetGroupShort | string | |
data.items[].symbolLong | string | Collateral token symbol |
data.items[].nameLong | string | Collateral token name |
data.items[].symbolShort | string | Debt token symbol |
data.items[].nameShort | string | Debt token name |
data.items[].aprBase | number | Leverage-weighted net APR % EXCLUDING rewards — the SUSTAINABLE rate (reward incentives are typically transient). |
data.items[].aprTotal | number | Leverage-weighted net APR % INCLUDING rewards. The reward contribution is aprTotal − aprBase. |
data.items[].maxLeverage | number | Highest leverage multiple reachable in this market. |
data.items[].ltv | number | Loan-to-value ratio, as a fraction between 0 and 1. |
data.items[].depositAprLong | number | Effective deposit APR (depositRate + intrinsicYield) |
data.items[].borrowAprShort | number | Effective borrow APR % (borrowRate + intrinsicYield − rewards, plus any 1y-amortized origination fee — see originationFeeShort). For Liquity-family CDPs the amortized origination fee is the whole borrow cost (variable rate is 0). |
data.items[].originationFeeShort | number | One-time origination / mint fee on the debt side, PERCENT (Liquity-family CDPs: River, Felix, Nerite, Ebisu, Soneta, USDAf, Liquity). NOT an APR — it is already folded (1y-amortized) into borrowAprShort / aprTotal, and surfaced raw so consumers can re-amortize over a different holding horizon. Null/absent for markets without one. |
data.items[].totalDepositsUsdLong | number | |
data.items[].totalDepositsUsdShort | number | |
data.items[].totalDebtUsdLong | number | |
data.items[].totalDebtUsdShort | number |
Example response
{
"success": true,
"data": {
"chainIds": [
"1"
],
"collaterals": [
"string"
],
"debts": [
"string"
],
"collateralAmount": 1.0,
"collateralAmountUsd": 1.0,
"debtAmount": 1.0,
"debtAmountUsd": 1.0,
"start": 1,
"count": 1,
"items": [
{
"chainId": "1",
"lender": "AAVE_V3",
"fixedTerm": {
"model": "term",
"maturity": 1,
"fees": {},
"earlyRepay": {},
"provider": {},
"auction": {
"status": "open",
"canBorrow": true,
"canLend": true,
"secondsUntilClose": 263000,
"implications": [
"string"
],
"id": "string",
"startTime": 1,
"revealTime": 1,
"endTime": 1,
"minBorrowAmount": "1000000000",
"minLendAmount": "1000000000"
}
},
"marketLongUid": "string",
"marketShortUid": "string",
"marketNameLong": "string",
"marketNameShort": "string",
"curatorNameLong": "string",
"curatorNameShort": "string",
"assetLong": "string",
"assetShort": "string",
"assetGroupLong": "string",
"assetGroupShort": "string",
"symbolLong": "string",
"nameLong": "string",
"symbolShort": "string",
"nameShort": "string",
"aprBase": 1.0,
"aprTotal": 1.0,
"maxLeverage": 1.0,
"ltv": 1.0,
"depositAprLong": 1.0,
"borrowAprShort": 1.0,
"originationFeeShort": 1.0,
"totalDepositsUsdLong": 1.0,
"totalDepositsUsdShort": 1.0,
"totalDebtUsdLong": 1.0,
"totalDebtUsdShort": 1.0,
"totalLiquidityUsdLong": 1.0,
"totalLiquidityUsdShort": 1.0,
"borrowLiquidityShort": 1.0,
"utilizationLong": 1.0,
"utilizationShort": 1.0,
"maxDebtAmount": 1.0,
"maxDebtAmountUsd": 1.0,
"minCollateralAmount": 1.0,
"minCollateralAmountUsd": 1.0,
"borrowAprAtAmount": 1.0,
"depositAprAtAmount": 1.0,
"netAprAtAmount": 1.0,
"netAprAtAmountBase": 1.0,
"borrowDepthShort": {},
"supplyDepthLong": {},
"risk": {
"maxTokenScore": 1,
"breakdown": [
{
"category": "lender",
"score": 1,
"label": "low",
"curatorIds": [
"string"
]
}
]
}
}
]
}
}
Request
Responses
- 200
- 400
- 429
- 500
- 502
Optimizer pairs
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.