# Collateral ⇄ debt optimizer

Endpoint reference for the 1delta API. Index: https://docs.1delta.io/llms.txt · every endpoint: https://docs.1delta.io/llms-full.txt

---

### GET /v1/data/lending/pairs/optimize

- operationId: `collateral-to-debt-optimizer`
- docs: https://docs.1delta.io/1delta-api/collateral-to-debt-optimizer/
- markdown: https://docs.1delta.io/1delta-api/collateral-to-debt-optimizer.md
- tags: Lending (Data)

Collateral ⇄ debt optimizer

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.

**Parameters**

| Name | 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`** — Optimizer pairs

| 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[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. |
| `data.items[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). |
| `data.items[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. |
| `data.items[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). |
| `data.items[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. |
| `data.items[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. |
| `data.items[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. |
| `data.items[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. |
| `data.items[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. |
| `data.items[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. |
| `data.items[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. |
| `data.items[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. |
| `data.items[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. |
| `data.items[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. |
| `data.items[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. |
| `data.items[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. |
| `data.items[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. |
| `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 |  |
| `data.items[].totalLiquidityUsdLong` | number |  |
| `data.items[].totalLiquidityUsdShort` | number |  |
| `data.items[].borrowLiquidityShort` | number |  |
| `data.items[].utilizationLong` | number |  |
| `data.items[].utilizationShort` | number |  |
| `data.items[].maxDebtAmount` | number | Max borrowable amount given collateral (only when collateralAmount/collateralAmountUsd param provided) |
| `data.items[].maxDebtAmountUsd` | number | USD value of maxDebtAmount |
| `data.items[].minCollateralAmount` | number | Min collateral needed for debt amount (only when debtAmount/debtAmountUsd param provided) |
| `data.items[].minCollateralAmountUsd` | number | USD value of minCollateralAmount |
| `data.items[].borrowAprAtAmount` | number | Effective borrow APR % at the computed debt notional: the headline borrowAprShort with only its organic (IRM) component re-priced at the post-borrow utilization (intrinsic + rewards are size-invariant). Present when an amount is supplied; null for non-curve lenders and brokered debt markets. |
| `data.items[].depositAprAtAmount` | number | Effective supply APR % at the collateral notional: the headline depositAprLong with only its organic (IRM) component re-priced at the post-deposit utilization. Present when an amount is supplied; null for non-curve lenders. |
| `data.items[].netAprAtAmount` | number | Leverage-weighted net position APR % on equity at the supplied amount, using the effective legs (INCLUDING rewards). Same components as aprTotal (directly comparable), but at the position's actual size/leverage. Null when equity is non-positive or a leg is unavailable. |
| `data.items[].netAprAtAmountBase` | number | Net APR % at the supplied amount EXCLUDING rewards — the sustainable at-size rate (netAprAtAmount with per-leg rewards stripped). The at-size reward contribution is netAprAtAmount − netAprAtAmountBase. Null when netAprAtAmount is. |
| `data.items[].borrowDepthShort` | object | Debt-market rate-vs-amount borrow grid. Only when depth=true. |
| `data.items[].supplyDepthLong` | object | Collateral-market rate-vs-amount supply grid. Only when depth=true. |
| `data.items[].risk` | object | Per-dimension risk for the pair. No composite headline score — take the worst (highest) breakdown entry if you need one. |
| `data.items[].risk.maxTokenScore` | integer | Worse of the two sides' token risk scores. |
| `data.items[].risk.breakdown` | object[] | One entry per dimension: config (market/e-mode configuration), chain, lender (protocol), tokenLong (collateral asset), tokenShort (debt asset), and curation — the last present ONLY for lenders that have curators (Morpho Blue, Euler). Scores are 1-5, higher = riskier; 0/null means unassessed and is labelled "unknown". |
| `data.items[].risk.breakdown[].category` | string |  |
| `data.items[].risk.breakdown[].score` | integer | Normalized risk score — lower is safer. |
| `data.items[].risk.breakdown[].label` | "low" \| "medium" \| "high" \| "unknown" |  |
| `data.items[].risk.breakdown[].curatorIds` | string[] | curation only: curator slugs of the pair's two markets, unioned. The pair's curation score is the WORSE of its two legs — an Euler position spanning a curated collateral vault and an uncurated controller is only as curated as the controller. |
| `actions` | null |  |

**Example response**

```json
{
  "success": true,
  "data": {
    "chainIds": [
      "1"
    ],
    "collaterals": [
      "string"
    ],
    "debts": [
      "string"
    ],
    "collateralAmount": 1,
    "collateralAmountUsd": 1,
    "debtAmount": 1,
    "debtAmountUsd": 1,
    "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,
        "aprTotal": 1,
        "maxLeverage": 1,
        "ltv": 1,
        "depositAprLong": 1,
        "borrowAprShort": 1,
        "originationFeeShort": 1,
        "totalDepositsUsdLong": 1,
        "totalDepositsUsdShort": 1,
        "totalDebtUsdLong": 1,
        "totalDebtUsdShort": 1,
        "totalLiquidityUsdLong": 1,
        "totalLiquidityUsdShort": 1,
        "borrowLiquidityShort": 1,
        "utilizationLong": 1,
        "utilizationShort": 1,
        "maxDebtAmount": 1,
        "maxDebtAmountUsd": 1,
        "minCollateralAmount": 1,
        "minCollateralAmountUsd": 1,
        "borrowAprAtAmount": 1,
        "depositAprAtAmount": 1,
        "netAprAtAmount": 1,
        "netAprAtAmountBase": 1,
        "borrowDepthShort": {},
        "supplyDepthLong": {},
        "risk": {
          "maxTokenScore": 1,
          "breakdown": [
            {
              "category": "lender",
              "score": 1,
              "label": "low",
              "curatorIds": [
                "string"
              ]
            }
          ]
        }
      }
    ]
  }
}
```

**Response `400`** — Validation error

**Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.

**Response `500`** — Unexpected server error. Safe to retry with backoff.

**Response `502`** — 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.
