{
  "openapi": "3.1.0",
  "info": {
    "title": "1delta API v1",
    "version": "1.0.0",
    "description": "Unified API for DeFi data and actions.\n\n## Machine-readable spec\n\n| Artefact | URL |\n| --- | --- |\n| OpenAPI 3.1 (enriched, what this site renders) | [`https://docs.1delta.io/openapi.json`](https://docs.1delta.io/openapi.json) |\n| OpenAPI 3.1 (raw, from the API server) | [`https://portal.1delta.io/v1/openapi.json`](https://portal.1delta.io/v1/openapi.json) |\n| Endpoint index for LLMs | [`https://docs.1delta.io/llms.txt`](https://docs.1delta.io/llms.txt) |\n| Full flattened reference for LLMs | [`https://docs.1delta.io/llms-full.txt`](https://docs.1delta.io/llms-full.txt) |\n\nIf you are pointing a coding agent at this API, give it `llms-full.txt` — it carries every endpoint, parameter, field and example as plain text, with no JavaScript required.\n\n## Authentication & rate limits\n\nEvery endpoint is public. Send an API key as the `x-api-key` header to raise your rate limit; get one at [auth.1delta.io](https://auth.1delta.io/). Unauthenticated traffic is limited per IP — treat `429` as retryable with exponential backoff rather than assuming a fixed budget.\n\nThere is no authentication *failure* mode: an unrecognised key is ignored rather than rejected, so a request never fails with `401` because of a bad key.\n\n## Response Envelope\n\nEvery endpoint returns a consistent JSON envelope. Integrators can rely on the same top-level shape regardless of the endpoint called.\n\n### Success\n\n```json\n{\n  \"success\": true,\n  \"data\": { ... },\n  \"actions\": { \"transactions\": [...], \"permissions\": [...] } | null\n}\n```\n\n- **`data`** — Informational payload (market data, quotes, simulation results, user positions, etc.). Present on all responses; `null` when the endpoint only produces transaction calldata with no additional info.\n- **`actions`** — Transaction calldata and approval/permission transactions that the caller should execute on-chain. Only populated by action endpoints; `null` on data endpoints.\n  - `actions.transactions` — Array of `{ to, data, value }` objects ready to be sent as EVM transactions.\n  - `actions.permissions` — Envelope-level array of approval/permission transactions (ERC-20 approves, credit delegations) that must be executed **before** the main transactions. Each entry has a human-readable `description`.\n\n> **Note on `permissions` vs `permissionTxns`:** the envelope exposes a single deduplicated `actions.permissions` array. Inside richer action responses (e.g. loop alternatives), each individual quote also carries its own `permissionTxns` — the per-quote subset needed if that specific alternative is executed. Most integrators only need `actions.permissions`.\n\n### Error\n\n```json\n{\n  \"success\": false,\n  \"error\": { \"code\": \"MISSING_PARAM\", \"message\": \"marketUid is required\" }\n}\n```\n\n- **`error.code`** — Machine-readable error code (e.g. `MISSING_PARAM`, `INVALID_PARAM`, `ACTION_FAILED`, `NOT_FOUND`, `ORIGIN_FAILED`).\n- **`error.message`** — Human-readable description.\n\nThe envelope is the same for every failure, so `success` is the only field you need to branch on. Note that a missing or malformed required parameter currently surfaces as HTTP `502` with `error.code = ORIGIN_FAILED` rather than a `400` — branch on `success`, not on the status code. See [Errors & retries](/errors).\n\n---\n\n## Identifiers\n\nMost endpoints address a market with a **`marketUid`**: `lender:chainId:address`, e.g. `AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`. The `lender` segment comes from the `LenderId` set and `address` is the underlying asset, not the receipt token. See [Market identifiers](/market-identifiers).\n\n---\n\n## Data (`/v1/data/*`)\nCacheable market data, prices, yields, and user positions. These endpoints always return `actions: null` — only the `data` field is populated.\n\n## Actions (`/v1/actions/*`)\nTransaction builders organized by category:\n- **Lending** — deposit, withdraw, borrow, repay, mode, enable-collateral, repay-with-atoken\n- **Loop** — leverage, close, collateral-swap, debt-swap, migrate (cross-lender), refinance (see also *Data › Loop* for range calculations)\n- **Swap** — spot (same-chain meta-aggregator), x-chain (bridge aggregation)\n- **Allocate** — batch operations\n\nAll action endpoints support **GET** (query parameters only) and **POST** (query parameters + JSON body for post-trade simulation). The `allocate` endpoint is POST-only.\n\nFor loop and swap operations, omit `account` for a **quote-only** response (`data` contains quotes, `actions` is `null`), or include it to build full transaction calldata (`actions` is populated with ready-to-send transactions).\n\nAction endpoints never sign or broadcast anything. They return calldata; your wallet or signer sends it. Execute `actions.permissions` first, then one transaction from `actions.transactions` (or exactly one entry from `actions.alternatives` where present). See the [Quickstart](/quickstart).\n\n## Simulation (POST)\nPOST the same query parameters as GET, plus a JSON body with the user's current `balanceData` and `aprData`. The response includes the standard fields plus a `simulation` object in `data` with projected post-trade health factor, borrow capacity, and APR data.\n\n## Execution Modes (lending only)\n- **direct** (default): Raw protocol interaction (deposit/withdraw/borrow/repay only)\n- **proxy**: Routes through 1delta composer contracts"
  },
  "servers": [
    {
      "url": "https://portal.1delta.io",
      "description": "Production"
    },
    {
      "url": "https://portal-staging.1delta.io",
      "description": "Staging"
    },
    {
      "url": "http://localhost:8787",
      "description": "Local Development"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Lending (Data)",
      "description": "Lending market and pool data"
    },
    {
      "name": "Loop (Data)",
      "description": "Range calculations for loop operations (leverage, close, collateral-swap, debt-swap)"
    },
    {
      "name": "Yields",
      "description": "Yield data by asset, lender, or intrinsic value"
    },
    {
      "name": "User Positions",
      "description": "User lending/borrowing positions"
    },
    {
      "name": "Prices",
      "description": "Asset price data and history"
    },
    {
      "name": "Token",
      "description": "Token lists, balances, and available lending assets"
    },
    {
      "name": "Vaults (Data)",
      "description": "Vault data and pending withdrawals across Fluid, Gearbox, Morpho, Silo, Euler Earn, LSTs, savings, Lagoon, HyperCore, and GMX"
    },
    {
      "name": "General",
      "description": "Health, metadata, and other data endpoints"
    },
    {
      "name": "Index",
      "description": "Endpoint directory for the Actions section"
    },
    {
      "name": "Lending (Actions)",
      "description": "Deposit, withdraw, borrow, repay, mode, enable-collateral"
    },
    {
      "name": "Loop (Actions)",
      "description": "Leverage, close, collateral-swap, debt-swap"
    },
    {
      "name": "Swap",
      "description": "Spot swap and cross-chain swap"
    },
    {
      "name": "Vaults (Actions)",
      "description": "Vault deposit/withdraw (ERC-4626 + ERC-7540/7575/HyperCore) and the LST, savings, and GMX action builders"
    },
    {
      "name": "Midnight",
      "description": "Morpho Midnight order-book: post/cancel your own limit offers (MAKE). Taking existing offers (lend/borrow) uses the standard Lending actions."
    },
    {
      "name": "Term",
      "description": "Term Finance auctions (sealed-bid lock → reveal) and secondary-listing management. Servicing (repay/redeem/collateral) and secondary-market lending use the standard Lending actions."
    },
    {
      "name": "Allocate",
      "description": "Batch multi-operation transactions"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Data",
      "tags": [
        "Lending (Data)",
        "Loop (Data)",
        "Yields",
        "User Positions",
        "Prices",
        "Token",
        "Vaults (Data)",
        "General"
      ]
    },
    {
      "name": "Actions",
      "tags": [
        "Index",
        "Lending (Actions)",
        "Loop (Actions)",
        "Swap",
        "Vaults (Actions)",
        "Midnight",
        "Term",
        "Allocate"
      ]
    }
  ],
  "paths": {
    "/v1/data/lending/latest": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get latest lending data (paginated by lender)",
        "operationId": "lending-latest",
        "description": "Returns latest per-market lending data for the requested chains, scoped to a specific page of lender keys.\n\n**Pagination**\n\nBoth `chains` and `lenders` are required. A maximum of **20 lender keys** may be supplied per request. Use [`GET /v1/data/lending/lenders`](/1delta-api/lending-lenders) to enumerate available lender keys (sorted by TVL) and page through them in batches of up to 20:\n\n```\nGET /v1/data/lending/lenders?chains=1,8453            → enumerate keys\nGET /v1/data/lending/latest?chains=1,8453&lenders=k1,…,k20    → page 1\nGET /v1/data/lending/latest?chains=1,8453&lenders=k21,…,k40   → page 2\n```\n\n**Breaking changes vs previous /lending/latest**\n\n- `lenders` is now required.\n- Hard cap of 20 lender keys per request.\n- Top-level `lenderKey` field is removed from items — use `lenderInfo.key`.\n\n**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.\n\n**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](/1delta-api/lending-deposit)/[borrow](/1delta-api/lending-borrow) actions, and to **MAKE** your own offer see [`/v1/actions/midnight/make`](/1delta-api/midnight-make).\n\n**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.\n\n**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).\n\n⚠ **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:\n\n- **`canBorrow`** — gate the borrow CTA on this, NOT on `status` or on the presence of a rate. It is true only while a round is accepting submissions.\n- **`canLend`** — deliberately independent of `canBorrow`: 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.\n- **`status`** — `upcoming` | `open` | `revealing` (bidding shut, prices revealing) | `closed` (no round listed).\n- **`secondsUntilClose`**, **`startTime`**, **`revealTime`** (the deadline to act), **`endTime`** — unix seconds; derive a live countdown from `revealTime` rather than trusting `secondsUntilClose` against a cached response.\n- **`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.\n- **`implications`** — ready-to-display string list, most important first (same convention as `params.market.teller.implications`).\n\n`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).\n\n**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.\n\nRead `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.\n\nEvery 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.\n\n**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.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/latest`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chains` | query | string[] | yes | Chain IDs to query (repeatable, CSV also accepted) |\n| `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. |\n| `maxRiskScore` | query | integer | no | Max risk score (1–5). Defaults to 4. |\n| `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. |\n| `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`. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `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). |\n| `data.count` | integer | Number of lender/chain entries |\n| `data.items` | object[] | Flat array of lender/chain entries |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lenderInfo` | object | Protocol/lender metadata (name, logo). |\n| `data.items[].lenderInfo.key` | string | Lender key identifier |\n| `data.items[].lenderInfo.name` | string | Human-readable lender name |\n| `data.items[].lenderInfo.logoURI` | string | Lender logo URL |\n| `data.items[].lastFetched` | number | Epoch ms of latest snapshot |\n| `data.items[].totalDepositsUsd` | number | Total deposits across all markets in USD |\n| `data.items[].totalDebtUsd` | number | Total debt across all markets in USD |\n| `data.items[].tvlUsd` | number | Total value locked in USD (deposits - debt) |\n| `data.items[].params` | object | Lender-specific parameters. Only present for Morpho/Lista lenders (e.g. `{ market: { … } }`). |\n| `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. |\n| `data.items[].markets` | object[] | Individual lending markets for this lender on this chain |\n| `data.items[].markets[].lenderKey` | string | Protocol identifier |\n| `data.items[].markets[].poolId` | string | Pool/vault address or protocol-specific ID |\n| `data.items[].markets[].depositRate` | number | Deposit APR (percent) |\n| `data.items[].markets[].variableBorrowRate` | number | Variable borrow APR (percent) |\n| `data.items[].markets[].stableBorrowRate` | number | Stable borrow APR (percent) |\n| `data.items[].markets[].intrinsicYield` | number | Intrinsic yield APR from underlying asset (e.g. stETH staking) |\n| `data.items[].markets[].totalDeposits` | number | Total deposits in token units |\n| `data.items[].markets[].totalDebtStable` | number | Total stable debt in token units |\n| `data.items[].markets[].totalDebt` | number | Total variable debt in token units |\n| `data.items[].markets[].totalLiquidity` | number | Available liquidity (totalDeposits - totalDebt) in token units |\n| `data.items[].markets[].totalDepositsUsd` | number | Total deposits in USD |\n| `data.items[].markets[].totalDebtStableUsd` | number | Total stable debt in USD |\n| `data.items[].markets[].totalDebtUsd` | number | Total variable debt in USD |\n| `data.items[].markets[].totalLiquidityUsd` | number | Available liquidity in USD |\n| `data.items[].markets[].utilization` | number | Utilization ratio (totalDebt / totalDeposits) |\n| `data.items[].markets[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. |\n| `data.items[].markets[].underlyingInfo` | object | Nested asset metadata, oracle prices, and market prices for a lending market. |\n| `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. |\n| `data.items[].markets[].caps` | object | Supply, borrow, and debt ceiling caps for a lending market. |\n| `data.items[].markets[].flags` | object | Boolean flags describing the operational status of a lending market. Values may be null if unavailable from the protocol. |\n| `data.items[].markets[].rewards` | object[] | Active reward programs. Defaults to [] when none. |\n| `data.items[].markets[].config` | object | Risk config keyed by mode/category ID (e.g. \"0\" for default, \"1\" for e-mode) |\n| `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. |\n| `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). |\n\n</details>\n",
        "parameters": [
          {
            "name": "chains",
            "in": "query",
            "required": true,
            "description": "Chain IDs to query (repeatable, CSV also accepted)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "8453"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "8453"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "required": true,
            "description": "Lender keys to fetch (repeatable, CSV also accepted). Max 20 per request. See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          },
          {
            "name": "maxRiskScore",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4,
              "example": 4
            },
            "description": "Max risk score (1–5). Defaults to 4.",
            "example": 4
          },
          {
            "name": "terms",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "digest",
                "full",
                "none"
              ],
              "default": "digest",
              "example": "full"
            },
            "description": "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.",
            "example": "full"
          },
          {
            "name": "includeOffers",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false,
              "example": true
            },
            "description": "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`.",
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "Latest lending data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LendingLatestResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "chainId": "8453",
                        "lenderInfo": {
                          "key": "AAVE_V3",
                          "name": "Aave V3",
                          "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp"
                        },
                        "lastFetched": 1,
                        "totalDepositsUsd": 1,
                        "totalDebtUsd": 1,
                        "tvlUsd": 1,
                        "params": {},
                        "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"
                          }
                        },
                        "markets": [
                          {
                            "lenderKey": "AAVE_V3",
                            "poolId": "string",
                            "depositRate": 1,
                            "variableBorrowRate": 1,
                            "stableBorrowRate": 1,
                            "intrinsicYield": 1,
                            "totalDeposits": 1,
                            "totalDebtStable": 1,
                            "totalDebt": 1,
                            "totalLiquidity": 1,
                            "totalDepositsUsd": 1,
                            "totalDebtStableUsd": 1,
                            "totalDebtUsd": 1,
                            "totalLiquidityUsd": 1,
                            "utilization": 1,
                            "decimals": 1,
                            "underlyingInfo": {
                              "asset": {
                                "chainId": "1",
                                "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                                "symbol": "USDC",
                                "name": "USD Coin",
                                "decimals": 6,
                                "logoURI": "string",
                                "assetGroup": "USDC",
                                "currencyId": "string",
                                "props": {}
                              },
                              "oraclePrice": {
                                "oraclePrice": 1,
                                "oraclePriceUsd": 1
                              },
                              "prices": {
                                "priceUsd": 1,
                                "priceTs": "2026-01-01T00:00:00Z",
                                "priceUsd24h": 1,
                                "priceTs24h": "2026-01-01T00:00:00Z",
                                "priceChange24h": 1
                              }
                            },
                            "oracleInfo": {
                              "feeds": [
                                {
                                  "asset": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                                  "oracle": "string",
                                  "provider": "string",
                                  "priceDescription": "string",
                                  "intendedPair": "string",
                                  "correctOracle": true,
                                  "denominatorMatch": true,
                                  "fixedRate": true,
                                  "score": 1,
                                  "band": "LOW",
                                  "flags": []
                                }
                              ],
                              "worstScore": 1,
                              "worstBand": "LOW"
                            },
                            "caps": {
                              "borrowCap": 1,
                              "supplyCap": 1,
                              "debtCeiling": "string"
                            },
                            "flags": {
                              "isActive": true,
                              "isFrozen": true,
                              "hasStable": true,
                              "borrowingEnabled": true,
                              "depositsEnabled": true,
                              "collateralActive": true,
                              "variableBorrowDisabled": true
                            },
                            "rewards": [
                              {
                                "asset": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                                "symbol": "string",
                                "decimals": 1,
                                "logoURI": "string",
                                "depositRate": 1,
                                "variableBorrowRate": 1,
                                "stableBorrowRate": 1,
                                "kind": "string",
                                "claim": "string",
                                "source": "string",
                                "sourceId": "string",
                                "sourceLabel": "string",
                                "link": "string",
                                "endsAt": 1,
                                "startsAt": 1,
                                "dailyRewardsUsd": 1,
                                "refs": {}
                              }
                            ],
                            "config": {},
                            "terms": [
                              {
                                "termId": 2,
                                "depositApr": 1,
                                "available": 1,
                                "durationDays": 7,
                                "durationSecs": 604800,
                                "apr": 3.85,
                                "aprAtAmount": 1,
                                "fillable": 1,
                                "capped": true,
                                "ladder": [
                                  {}
                                ]
                              }
                            ],
                            "broker": "0x1fa26015286d1270343d7526c60bd57ab6be8b54",
                            "collateralProvider": "0x33f7a980a246f9b8fea2254e3065576e127d4d5f",
                            "loanProvider": "0x367384c54756a25340c63057d87ea22d47fd5701",
                            "closeFactor": 0.5,
                            "targetHealthFactor": 1.05,
                            "lenderInfo": {
                              "key": "AAVE_V3",
                              "name": "Aave V3",
                              "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp"
                            },
                            "termSheet": {
                              "schemaVersion": 1,
                              "profileId": "string",
                              "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                              "supply": {},
                              "borrow": {},
                              "oracle": {},
                              "governance": {},
                              "utilization": 1
                            }
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/lending/lenders": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Enumerate available lenders",
        "operationId": "lending-lenders",
        "description": "Lightweight enumeration of every `(chainId, lenderKey)` pair that has data for the requested chains, sorted by `tvlUsd` descending.\n\nUse this endpoint to discover the lender keys to page through [`GET /v1/data/lending/latest`](/1delta-api/lending-latest), which is hard-capped at 20 lender keys per request.\n\n```\nGET /v1/data/lending/lenders?chains=1,8453            → enumerate keys\nGET /v1/data/lending/latest?chains=1,8453&lenders=k1,…,k20    → page 1\nGET /v1/data/lending/latest?chains=1,8453&lenders=k21,…,k40   → page 2\n```\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/lenders`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chains` | query | string[] | yes | Chain IDs to query (repeatable, CSV also accepted) |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable, CSV also accepted). Defaults to all lenders. See the `LenderId` schema for the full set of accepted values. |\n| `maxRiskScore` | query | integer | no | Max risk score (1–5). Defaults to 4. |\n| `minTvl` | query | number | no | Filter out lender entries with `tvlUsd` below this USD threshold. Applied as a HAVING clause after aggregation. Returns 400 if non-numeric. |\n| `count` | query | integer | no | Optional cap on the number of items returned. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Enumeration of available (chainId, lenderKey) pairs sorted by tvlUsd descending. |\n| `data.count` | integer | Number of items returned |\n| `data.items` | object[] | Lender entries sorted by tvlUsd descending |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lenderInfo` | object | Protocol/lender metadata (name, logo). |\n| `data.items[].lenderInfo.key` | string | Lender key identifier |\n| `data.items[].lenderInfo.name` | string | Human-readable lender name |\n| `data.items[].lenderInfo.logoURI` | string | Lender logo URL |\n| `data.items[].tvlUsd` | number | Σ totalDepositsUsd − Σ totalDebtUsd over the lender's markets on this chain |\n| `data.items[].lastFetched` | number | Epoch ms of latest snapshot |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": [\n      {\n        \"chainId\": \"1\",\n        \"lenderInfo\": {\n          \"key\": \"AAVE_V3\",\n          \"name\": \"Aave V3\",\n          \"logoURI\": \"https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp\"\n        },\n        \"tvlUsd\": 1234567890.12,\n        \"lastFetched\": 1.0\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chains",
            "in": "query",
            "required": true,
            "description": "Chain IDs to query (repeatable, CSV also accepted)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "10",
                "8453"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "10",
              "8453"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable, CSV also accepted). Defaults to all lenders. See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3"
            ]
          },
          {
            "name": "maxRiskScore",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4,
              "example": 4
            },
            "description": "Max risk score (1–5). Defaults to 4.",
            "example": 4
          },
          {
            "name": "minTvl",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 1000000
            },
            "description": "Filter out lender entries with `tvlUsd` below this USD threshold. Applied as a HAVING clause after aggregation. Returns 400 if non-numeric.",
            "example": 1000000
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 20
            },
            "description": "Optional cap on the number of items returned.",
            "example": 20
          }
        ],
        "responses": {
          "200": {
            "description": "Available lenders sorted by TVL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LendingLendersResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "chainId": "1",
                        "lenderInfo": {
                          "key": "AAVE_V3",
                          "name": "Aave V3",
                          "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp"
                        },
                        "tvlUsd": 1234567890.12,
                        "lastFetched": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/lending/pools": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get lending pools",
        "description": "Returns paginated lending pool data with optional filters and sorting.\n\n**Server-side defaults** (applied when the parameter is omitted; pass an explicit value to override):\n| Parameter | Default |\n|-----------|---------|\n| `minUtil` | `0.1` |\n| `maxUtil` | `0.9` |\n| `minTvlUsd` | `100000` (Ethereum, chainId 1) / `25000` (all other chains) |\n| `maxRiskScore` | `4` (medium) |\n\nTo disable a default filter, pass `0` (e.g. `minUtil=0`).\n\n**Oracle risk:** each pool 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.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/pools`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | no | Filter by lender key (e.g. AAVE_V3) See the `LenderId` schema for the full set of accepted values. |\n| `underlyings` | query | string | no | Comma-separated token addresses (0x-prefixed) |\n| `assetGroups` | query | string | no | Comma-separated asset group names |\n| `minYield` | query | number | no | Minimum deposit rate |\n| `maxYield` | query | number | no | Maximum deposit rate |\n| `minUtil` | query | number | no | Minimum utilization (0-1). Defaults to 0.1 when omitted. |\n| `maxUtil` | query | number | no | Maximum utilization (0-1). Defaults to 0.9 when omitted. |\n| `minTvlUsd` | query | number | no | Minimum total liquidity in USD. Defaults to 100000 on Ethereum (chainId 1), 25000 on other chains. |\n| `maxTvlUsd` | query | number | no | Maximum total liquidity in USD |\n| `minDeposits` | query | number | no | Minimum total deposits (native units) |\n| `maxDeposits` | query | number | no | Maximum total deposits (native units) |\n| `minDebt` | query | number | no | Minimum total debt (native units) |\n| `maxDebt` | query | number | no | Maximum total debt (native units) |\n| `minLiquidity` | query | number | no | Minimum total liquidity (native units) |\n| `maxLiquidity` | query | number | no | Maximum total liquidity (native units) |\n| `minDebtUsd` | query | number | no | Minimum total debt in USD |\n| `maxDebtUsd` | query | number | no | Maximum total debt in USD |\n| `minLiquidityUsd` | query | number | no | Minimum total liquidity in USD |\n| `maxLiquidityUsd` | query | number | no | Maximum total liquidity in USD |\n| `maxRiskScore` | query | integer | no | Maximum risk score (1–5). Defaults to 4 (medium) when omitted. |\n| `includeExposures` | query | boolean | no | Include config exposure data per pool. Opt-in; omit or false to skip (expensive). |\n| `sortBy` | query | `depositRate`, `variableBorrowRate`, `stableBorrowRate`, `intrinsicYield`, `utilization`, `totalDeposits`, … (11 values) | no | Sort field |\n| `sortDir` | query | `ASC`, `DESC` | no | Sort direction |\n| `start` | query | integer | no | Pagination offset |\n| `count` | query | integer | no | Page size (default 100, max 1000) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.start` | integer |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.pools` | object[] |  |\n| `data.pools[].chain_id` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.pools[].lender_key` | string |  |\n| `data.pools[].underlying_address` | string |  |\n| `data.pools[].asset_group` | string |  |\n| `data.pools[].deposit_rate` | number |  |\n| `data.pools[].variable_borrow_rate` | number |  |\n| `data.pools[].stable_borrow_rate` | number |  |\n| `data.pools[].intrinsic_yield` | number |  |\n| `data.pools[].utilization` | number | Market utilization, as a fraction between 0 and 1. |\n| `data.pools[].total_deposits` | number |  |\n| `data.pools[].total_debt` | number |  |\n| `data.pools[].total_liquidity` | number |  |\n| `data.pools[].total_deposits_usd` | number |  |\n| `data.pools[].total_debt_usd` | number |  |\n| `data.pools[].total_liquidity_usd` | number |  |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"start\": 1,\n    \"count\": 1,\n    \"pools\": [\n      {\n        \"chain_id\": \"string\",\n        \"lender_key\": \"AAVE_V3\",\n        \"underlying_address\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"asset_group\": \"string\",\n        \"deposit_rate\": 1.0,\n        \"variable_borrow_rate\": 1.0,\n        \"stable_borrow_rate\": 1.0,\n        \"intrinsic_yield\": 1.0,\n        \"utilization\": 1.0,\n        \"total_deposits\": 1.0,\n        \"total_debt\": 1.0,\n        \"total_liquidity\": 1.0,\n        \"total_deposits_usd\": 1.0,\n        \"total_debt_usd\": 1.0,\n        \"total_liquidity_usd\": 1.0\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Filter by chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Filter by lender key (e.g. AAVE_V3) See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "underlyings",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated token addresses (0x-prefixed)"
          },
          {
            "name": "assetGroups",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "ETH"
            },
            "description": "Comma-separated asset group names",
            "example": "ETH"
          },
          {
            "name": "minYield",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum deposit rate"
          },
          {
            "name": "maxYield",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum deposit rate"
          },
          {
            "name": "minUtil",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0.1
            },
            "description": "Minimum utilization (0-1). Defaults to 0.1 when omitted."
          },
          {
            "name": "maxUtil",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0.9
            },
            "description": "Maximum utilization (0-1). Defaults to 0.9 when omitted."
          },
          {
            "name": "minTvlUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total liquidity in USD. Defaults to 100000 on Ethereum (chainId 1), 25000 on other chains."
          },
          {
            "name": "maxTvlUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total liquidity in USD"
          },
          {
            "name": "minDeposits",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total deposits (native units)"
          },
          {
            "name": "maxDeposits",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total deposits (native units)"
          },
          {
            "name": "minDebt",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total debt (native units)"
          },
          {
            "name": "maxDebt",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total debt (native units)"
          },
          {
            "name": "minLiquidity",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total liquidity (native units)"
          },
          {
            "name": "maxLiquidity",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total liquidity (native units)"
          },
          {
            "name": "minDebtUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total debt in USD"
          },
          {
            "name": "maxDebtUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total debt in USD"
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total liquidity in USD"
          },
          {
            "name": "maxLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total liquidity in USD"
          },
          {
            "name": "maxRiskScore",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4
            },
            "description": "Maximum risk score (1–5). Defaults to 4 (medium) when omitted."
          },
          {
            "name": "includeExposures",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include config exposure data per pool. Opt-in; omit or false to skip (expensive)."
          },
          {
            "name": "sortBy",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "depositRate",
                "variableBorrowRate",
                "stableBorrowRate",
                "intrinsicYield",
                "utilization",
                "totalDeposits",
                "totalDebt",
                "totalLiquidity",
                "totalDepositsUsd",
                "totalDebtUsd",
                "totalLiquidityUsd"
              ],
              "default": "totalDepositsUsd"
            },
            "description": "Sort field"
          },
          {
            "name": "sortDir",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ASC",
                "DESC"
              ],
              "default": "DESC"
            },
            "description": "Sort direction"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Pagination offset"
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "example": 10
            },
            "description": "Page size (default 100, max 1000)",
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "Pool data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/PoolsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "start": 1,
                    "count": 1,
                    "pools": [
                      {
                        "chain_id": "string",
                        "lender_key": "AAVE_V3",
                        "underlying_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "asset_group": "string",
                        "deposit_rate": 1,
                        "variable_borrow_rate": 1,
                        "stable_borrow_rate": 1,
                        "intrinsic_yield": 1,
                        "utilization": 1,
                        "total_deposits": 1,
                        "total_debt": 1,
                        "total_liquidity": 1,
                        "total_deposits_usd": 1,
                        "total_debt_usd": 1,
                        "total_liquidity_usd": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-lending-pools"
      }
    },
    "/v1/data/lending/pools/by-config": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get pools grouped by config",
        "description": "For each (lender, chain, configId) combination, returns which markets are eligible as collateral or borrowable.\n\nEach item includes a `collaterals` and `borrowables` array with per-market rate, factor, and TVL data. Either array is `null` when no markets qualify. A market absent from a config entry has both collateral and debt disabled for that config.\n\nUseful for building position-builder UIs that need to know which assets can be paired within a given pool configuration (e.g. e-mode categories, isolated pools).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/pools/by-config`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chains` | query | string | no | Comma-separated chain IDs |\n| `lenders` | query | string | no | Comma-separated lender keys See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chains",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,8453"
            },
            "description": "Comma-separated chain IDs",
            "example": "1,8453"
          },
          {
            "name": "lenders",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Comma-separated lender keys See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          }
        ],
        "responses": {
          "200": {
            "description": "Config pool breakdown per lender/chain/configId",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-pools-grouped-by-config"
      }
    },
    "/v1/data/lending/pairs": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get lending pairs",
        "description": "Returns paginated leverage pair data with optional filters and sorting. Backed by the same origin route as `/v1/data/lending/pairs/leverage`, so it shares that endpoint's behaviour — including dropping pairs whose collateral leg has no remaining supply capacity (`includeIlliquid=true` keeps them).\n\n**Lista DAO fixed-term (brokered) debt side:** when the short (debt) market is brokered, `variableBorrowDisabledShort` is `true` and `termsShort[]` lists the fixed-term loop options (each a `MarketTerm`). The pair has one loop option per term rather than a single variable-rate loop — use the per-term APR from `termsShort[]` in place of `variableBorrowRateShort` (which is `0`/undefined for these pairs).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/pairs`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | no | Filter by lender key See the `LenderId` schema for the full set of accepted values. |\n| `assetGroupLong` | query | string | no | Filter by collateral asset group |\n| `assetGroupShort` | query | string | no | Filter by debt asset group |\n| `minApr` | query | number | no | Minimum total APR |\n| `minLeverage` | query | number | no | Minimum max leverage |\n| `minLiquidityUsd` | query | number | no | Minimum liquidity in USD |\n| `includeIlliquid` | query | boolean | no | Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default. |\n| `sortBy` | query | `aprTotal`, `maxLeverage`, `totalDepositsUsdLong`, `totalDebtUsdShort` | no | Sort field |\n| `sortDir` | query | `asc`, `desc` | no | Sort direction |\n| `start` | query | integer | no | Pagination start index |\n| `count` | query | integer | no | Page size |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.start` | integer |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.items[].marketLongUid` | string | Market UID of the collateral side |\n| `data.items[].marketShortUid` | string | Market UID of the debt side |\n| `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. |\n| `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. |\n| `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. |\n| `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data.items[].assetLong` | string | Collateral asset address |\n| `data.items[].assetShort` | string | Debt asset address |\n| `data.items[].assetGroupLong` | string |  |\n| `data.items[].assetGroupShort` | string |  |\n| `data.items[].symbolLong` | string | Collateral token symbol |\n| `data.items[].nameLong` | string | Collateral token name |\n| `data.items[].symbolShort` | string | Debt token symbol |\n| `data.items[].nameShort` | string | Debt token name |\n| `data.items[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data.items[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data.items[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data.items[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data.items[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data.items[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data.items[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data.items[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data.items[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data.items[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data.items[].eModeConfigId` | string | E-mode configuration ID |\n| `data.items[].eMode` | string | E-mode category |\n| `data.items[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data.items[].aprTotal` | number | Total APR (base + rewards) |\n| `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data.items[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data.items[].depositRateLong` | number |  |\n| `data.items[].variableBorrowRateShort` | number |  |\n| `data.items[].intrinsicYieldLong` | number |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"start\": 1,\n    \"count\": 1,\n    \"items\": [\n      {\n        \"chainId\": \"1\",\n        \"lender\": \"AAVE_V3\",\n        \"marketLongUid\": \"string\",\n        \"marketShortUid\": \"string\",\n        \"marketNameLong\": \"string\",\n        \"marketNameShort\": \"string\",\n        \"curatorNameLong\": \"string\",\n        \"curatorNameShort\": \"string\",\n        \"assetLong\": \"string\",\n        \"assetShort\": \"string\",\n        \"assetGroupLong\": \"string\",\n        \"assetGroupShort\": \"string\",\n        \"symbolLong\": \"string\",\n        \"nameLong\": \"string\",\n        \"symbolShort\": \"string\",\n        \"nameShort\": \"string\",\n        \"collateralFactorLong\": 0.94,\n        \"borrowCollateralFactorLong\": 0.92,\n        \"borrowFactorLong\": 1,\n        \"collateralDisabledLong\": true,\n        \"debtDisabledLong\": true,\n        \"collateralFactorShort\": 0.94,\n        \"borrowCollateralFactorShort\": 0.92,\n        \"borrowFactorShort\": 1,\n        \"collateralDisabledShort\": true,\n        \"debtDisabledShort\": true,\n        \"eModeConfigId\": \"string\",\n        \"eMode\": \"string\",\n        \"aprBase\": 1.0,\n        \"aprTotal\": 1.0,\n        \"maxLeverage\": 1.0,\n        \"ltv\": 1.0,\n        \"depositRateLong\": 1.0,\n        \"variableBorrowRateShort\": 1.0,\n        \"intrinsicYieldLong\": 1.0,\n        \"intrinsicYieldShort\": 1.0,\n        \"variableBorrowDisabledShort\": true,\n        \"termsShort\": [\n          {\n            \"termId\": 2,\n            \"depositApr\": 1.0,\n            \"available\": 1.0,\n            \"durationDays\": 7,\n            \"durationSecs\": 604800,\n            \"apr\": 3.85,\n            \"aprAtAmount\": 1.0,\n            \"fillable\": 1.0,\n            \"capped\": true,\n            \"ladder\": [\n              {\n                \"apr\": 1.0,\n                \"units\": \"string\",\n                \"assets\": 1.0\n              }\n            ]\n          }\n        ],\n        \"fixedTerm\": {\n          \"model\": \"term\",\n          \"maturity\": 1,\n          \"fees\": {},\n          \"earlyRepay\": {},\n          \"provider\": {},\n          \"auction\": {\n            \"status\": \"open\",\n            \"canBorrow\": true,\n            \"canLend\": true,\n            \"secondsUntilClose\": 263000,\n            \"implications\": [\n              \"string\"\n            ],\n            \"id\": \"string\",\n            \"startTime\": 1,\n            \"revealTime\": 1,\n            \"endTime\": 1,\n            \"minBorrowAmount\": \"1000000000\",\n            \"minLendAmount\": \"1000000000\"\n          }\n        },\n        \"rewardAprLong\": 1.0,\n        \"rewardAprShort\": 1.0,\n        \"rewardsLong\": [\n          {}\n        ],\n        \"rewardsShort\": [\n          {}\n        ],\n        \"totalDepositsLong\": 1.0,\n        \"totalDebtLong\": 1.0,\n        \"totalLiquidityLong\": 1.0,\n        \"totalDepositsShort\": 1.0,\n        \"totalDebtShort\": 1.0,\n        \"totalLiquidityShort\": 1.0,\n        \"totalDepositsUsdLong\": 1.0,\n        \"totalDebtUsdLong\": 1.0,\n        \"totalLiquidityUsdLong\": 1.0,\n        \"totalDepositsUsdShort\": 1.0,\n        \"totalDebtUsdShort\": 1.0,\n        \"totalLiquidityUsdShort\": 1.0,\n        \"borrowLiquidityShort\": 1.0,\n        \"withdrawLiquidityLong\": 1.0,\n        \"depositableLong\": 1.0,\n        \"utilizationLong\": 1.0,\n        \"utilizationShort\": 1.0,\n        \"underlyingInfoLong\": {\n          \"asset\": {},\n          \"prices\": {},\n          \"oraclePrice\": {}\n        },\n        \"underlyingInfoShort\": {\n          \"asset\": {},\n          \"prices\": {},\n          \"oraclePrice\": {}\n        }\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Filter by chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Filter by lender key See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "assetGroupLong",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "ETH"
            },
            "description": "Filter by collateral asset group",
            "example": "ETH"
          },
          {
            "name": "assetGroupShort",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC"
            },
            "description": "Filter by debt asset group",
            "example": "USDC"
          },
          {
            "name": "minApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total APR"
          },
          {
            "name": "minLeverage",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum max leverage"
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum liquidity in USD"
          },
          {
            "name": "includeIlliquid",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default."
          },
          {
            "name": "sortBy",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "aprTotal",
                "maxLeverage",
                "totalDepositsUsdLong",
                "totalDebtUsdShort"
              ],
              "example": "aprTotal"
            },
            "description": "Sort field",
            "example": "aprTotal"
          },
          {
            "name": "sortDir",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Pagination start index"
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "example": 10
            },
            "description": "Page size",
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "Pair data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LeveragePairsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "start": 1,
                    "count": 1,
                    "items": [
                      {
                        "chainId": "1",
                        "lender": "AAVE_V3",
                        "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",
                        "collateralFactorLong": 0.94,
                        "borrowCollateralFactorLong": 0.92,
                        "borrowFactorLong": 1,
                        "collateralDisabledLong": true,
                        "debtDisabledLong": true,
                        "collateralFactorShort": 0.94,
                        "borrowCollateralFactorShort": 0.92,
                        "borrowFactorShort": 1,
                        "collateralDisabledShort": true,
                        "debtDisabledShort": true,
                        "eModeConfigId": "string",
                        "eMode": "string",
                        "aprBase": 1,
                        "aprTotal": 1,
                        "maxLeverage": 1,
                        "ltv": 1,
                        "depositRateLong": 1,
                        "variableBorrowRateShort": 1,
                        "intrinsicYieldLong": 1,
                        "intrinsicYieldShort": 1,
                        "variableBorrowDisabledShort": true,
                        "termsShort": [
                          {
                            "termId": 2,
                            "depositApr": 1,
                            "available": 1,
                            "durationDays": 7,
                            "durationSecs": 604800,
                            "apr": 3.85,
                            "aprAtAmount": 1,
                            "fillable": 1,
                            "capped": true,
                            "ladder": [
                              {
                                "apr": 1,
                                "units": "string",
                                "assets": 1
                              }
                            ]
                          }
                        ],
                        "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"
                          }
                        },
                        "rewardAprLong": 1,
                        "rewardAprShort": 1,
                        "rewardsLong": [
                          {}
                        ],
                        "rewardsShort": [
                          {}
                        ],
                        "totalDepositsLong": 1,
                        "totalDebtLong": 1,
                        "totalLiquidityLong": 1,
                        "totalDepositsShort": 1,
                        "totalDebtShort": 1,
                        "totalLiquidityShort": 1,
                        "totalDepositsUsdLong": 1,
                        "totalDebtUsdLong": 1,
                        "totalLiquidityUsdLong": 1,
                        "totalDepositsUsdShort": 1,
                        "totalDebtUsdShort": 1,
                        "totalLiquidityUsdShort": 1,
                        "borrowLiquidityShort": 1,
                        "withdrawLiquidityLong": 1,
                        "depositableLong": 1,
                        "utilizationLong": 1,
                        "utilizationShort": 1,
                        "underlyingInfoLong": {
                          "asset": {},
                          "prices": {},
                          "oraclePrice": {}
                        },
                        "underlyingInfoShort": {
                          "asset": {},
                          "prices": {},
                          "oraclePrice": {}
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-lending-pairs"
      }
    },
    "/v1/data/lending/pairs/leverage": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Browse all leverage pairs",
        "description": "Returns raw materialized view rows with all rate and liquidity fields. Supports single-chain address filtering or cross-chain asset-group mode.\n\nPairs whose COLLATERAL leg has no remaining supply capacity (`depositableLong <= 0`) are dropped by default — a market that cannot take the deposit is not an opportunity at any rate, and those rows sort to the top of an APR ranking precisely because nobody can reach them. `depositableLong: null` means uncapped, i.e. unlimited, and always passes. `includeIlliquid=true` keeps them.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/pairs/leverage`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Single chain ID (address-based filtering). Omit for cross-chain asset-group mode. See the `ChainId` schema for the full set of supported chains. |\n| `chainIds` | query | string | no | Comma-separated chain IDs for multi-chain (asset-group filtering) See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | no | Lender filter (UPPER_SNAKE_CASE) See the `LenderId` schema for the full set of accepted values. |\n| `minApr` | query | number | no | Minimum total APR |\n| `maxApr` | query | number | no | Maximum total APR |\n| `minLeverage` | query | number | no | Minimum leverage |\n| `assetLong` | query | string | no | Long asset address (single-chain mode) |\n| `assetShort` | query | string | no | Short asset address (single-chain mode) |\n| `assetGroupLong` | query | string | no | Long asset group (ILIKE partial match) |\n| `assetGroupShort` | query | string | no | Short asset group (ILIKE partial match) |\n| `minDepositApr` | query | number | no | Min effective deposit APR (deposit_rate + intrinsic_yield) |\n| `minLtv` | query | number | no | Minimum LTV ratio (0-1) |\n| `maxBorrowRate` | query | number | no | Max effective borrow rate (borrow_rate + intrinsic_yield) |\n| `includeIlliquid` | query | boolean | no | Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default. |\n| `minLiquidityUsdLong` | query | number | no | Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — see `includeIlliquid` for the capacity gate. |\n| `minDepositsUsdLong` | query | number | no | Min collateral-side deposits USD |\n| `maxUtilizationLong` | query | number | no | Max collateral-side utilization (0-1) |\n| `minBorrowLiquidityUsd` | query | number | no | Min debt-side borrow liquidity USD |\n| `minDebtUsdShort` | query | number | no | Min debt-side total debt USD |\n| `maxUtilizationShort` | query | number | no | Max debt-side utilization (0-1) |\n| `start` | query | integer | no | Pagination offset |\n| `count` | query | integer | no | Page size (max 100) |\n| `sortBy` | query | `aprTotal`, `maxLeverage`, `depositRateLong`, `variableBorrowRateShort`, `intrinsicYieldLong`, `intrinsicYieldShort`, … (13 values) | no | Sort field |\n| `sortDir` | query | `ASC`, `DESC` | no | Sort direction |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.start` | integer |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.items[].marketLongUid` | string | Market UID of the collateral side |\n| `data.items[].marketShortUid` | string | Market UID of the debt side |\n| `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. |\n| `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. |\n| `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. |\n| `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data.items[].assetLong` | string | Collateral asset address |\n| `data.items[].assetShort` | string | Debt asset address |\n| `data.items[].assetGroupLong` | string |  |\n| `data.items[].assetGroupShort` | string |  |\n| `data.items[].symbolLong` | string | Collateral token symbol |\n| `data.items[].nameLong` | string | Collateral token name |\n| `data.items[].symbolShort` | string | Debt token symbol |\n| `data.items[].nameShort` | string | Debt token name |\n| `data.items[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data.items[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data.items[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data.items[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data.items[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data.items[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data.items[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data.items[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data.items[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data.items[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data.items[].eModeConfigId` | string | E-mode configuration ID |\n| `data.items[].eMode` | string | E-mode category |\n| `data.items[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data.items[].aprTotal` | number | Total APR (base + rewards) |\n| `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data.items[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data.items[].depositRateLong` | number |  |\n| `data.items[].variableBorrowRateShort` | number |  |\n| `data.items[].intrinsicYieldLong` | number |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"start\": 1,\n    \"count\": 1,\n    \"items\": [\n      {\n        \"chainId\": \"1\",\n        \"lender\": \"AAVE_V3\",\n        \"marketLongUid\": \"string\",\n        \"marketShortUid\": \"string\",\n        \"marketNameLong\": \"string\",\n        \"marketNameShort\": \"string\",\n        \"curatorNameLong\": \"string\",\n        \"curatorNameShort\": \"string\",\n        \"assetLong\": \"string\",\n        \"assetShort\": \"string\",\n        \"assetGroupLong\": \"string\",\n        \"assetGroupShort\": \"string\",\n        \"symbolLong\": \"string\",\n        \"nameLong\": \"string\",\n        \"symbolShort\": \"string\",\n        \"nameShort\": \"string\",\n        \"collateralFactorLong\": 0.94,\n        \"borrowCollateralFactorLong\": 0.92,\n        \"borrowFactorLong\": 1,\n        \"collateralDisabledLong\": true,\n        \"debtDisabledLong\": true,\n        \"collateralFactorShort\": 0.94,\n        \"borrowCollateralFactorShort\": 0.92,\n        \"borrowFactorShort\": 1,\n        \"collateralDisabledShort\": true,\n        \"debtDisabledShort\": true,\n        \"eModeConfigId\": \"string\",\n        \"eMode\": \"string\",\n        \"aprBase\": 1.0,\n        \"aprTotal\": 1.0,\n        \"maxLeverage\": 1.0,\n        \"ltv\": 1.0,\n        \"depositRateLong\": 1.0,\n        \"variableBorrowRateShort\": 1.0,\n        \"intrinsicYieldLong\": 1.0,\n        \"intrinsicYieldShort\": 1.0,\n        \"variableBorrowDisabledShort\": true,\n        \"termsShort\": [\n          {\n            \"termId\": 2,\n            \"depositApr\": 1.0,\n            \"available\": 1.0,\n            \"durationDays\": 7,\n            \"durationSecs\": 604800,\n            \"apr\": 3.85,\n            \"aprAtAmount\": 1.0,\n            \"fillable\": 1.0,\n            \"capped\": true,\n            \"ladder\": [\n              {\n                \"apr\": 1.0,\n                \"units\": \"string\",\n                \"assets\": 1.0\n              }\n            ]\n          }\n        ],\n        \"fixedTerm\": {\n          \"model\": \"term\",\n          \"maturity\": 1,\n          \"fees\": {},\n          \"earlyRepay\": {},\n          \"provider\": {},\n          \"auction\": {\n            \"status\": \"open\",\n            \"canBorrow\": true,\n            \"canLend\": true,\n            \"secondsUntilClose\": 263000,\n            \"implications\": [\n              \"string\"\n            ],\n            \"id\": \"string\",\n            \"startTime\": 1,\n            \"revealTime\": 1,\n            \"endTime\": 1,\n            \"minBorrowAmount\": \"1000000000\",\n            \"minLendAmount\": \"1000000000\"\n          }\n        },\n        \"rewardAprLong\": 1.0,\n        \"rewardAprShort\": 1.0,\n        \"rewardsLong\": [\n          {}\n        ],\n        \"rewardsShort\": [\n          {}\n        ],\n        \"totalDepositsLong\": 1.0,\n        \"totalDebtLong\": 1.0,\n        \"totalLiquidityLong\": 1.0,\n        \"totalDepositsShort\": 1.0,\n        \"totalDebtShort\": 1.0,\n        \"totalLiquidityShort\": 1.0,\n        \"totalDepositsUsdLong\": 1.0,\n        \"totalDebtUsdLong\": 1.0,\n        \"totalLiquidityUsdLong\": 1.0,\n        \"totalDepositsUsdShort\": 1.0,\n        \"totalDebtUsdShort\": 1.0,\n        \"totalLiquidityUsdShort\": 1.0,\n        \"borrowLiquidityShort\": 1.0,\n        \"withdrawLiquidityLong\": 1.0,\n        \"depositableLong\": 1.0,\n        \"utilizationLong\": 1.0,\n        \"utilizationShort\": 1.0,\n        \"underlyingInfoLong\": {\n          \"asset\": {},\n          \"prices\": {},\n          \"oraclePrice\": {}\n        },\n        \"underlyingInfoShort\": {\n          \"asset\": {},\n          \"prices\": {},\n          \"oraclePrice\": {}\n        }\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Single chain ID (address-based filtering). Omit for cross-chain asset-group mode. See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "chainIds",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated chain IDs for multi-chain (asset-group filtering) See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Lender filter (UPPER_SNAKE_CASE) See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "minApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total APR"
          },
          {
            "name": "maxApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total APR"
          },
          {
            "name": "minLeverage",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum leverage"
          },
          {
            "name": "assetLong",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Long asset address (single-chain mode)"
          },
          {
            "name": "assetShort",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Short asset address (single-chain mode)"
          },
          {
            "name": "assetGroupLong",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "ETH"
            },
            "description": "Long asset group (ILIKE partial match)",
            "example": "ETH"
          },
          {
            "name": "assetGroupShort",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC"
            },
            "description": "Short asset group (ILIKE partial match)",
            "example": "USDC"
          },
          {
            "name": "minDepositApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min effective deposit APR (deposit_rate + intrinsic_yield)"
          },
          {
            "name": "minLtv",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum LTV ratio (0-1)"
          },
          {
            "name": "maxBorrowRate",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max effective borrow rate (borrow_rate + intrinsic_yield)"
          },
          {
            "name": "includeIlliquid",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default."
          },
          {
            "name": "minLiquidityUsdLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — see `includeIlliquid` for the capacity gate."
          },
          {
            "name": "minDepositsUsdLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min collateral-side deposits USD"
          },
          {
            "name": "maxUtilizationLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max collateral-side utilization (0-1)"
          },
          {
            "name": "minBorrowLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min debt-side borrow liquidity USD"
          },
          {
            "name": "minDebtUsdShort",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min debt-side total debt USD"
          },
          {
            "name": "maxUtilizationShort",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max debt-side utilization (0-1)"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Pagination offset"
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size (max 100)"
          },
          {
            "name": "sortBy",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "aprTotal",
                "maxLeverage",
                "depositRateLong",
                "variableBorrowRateShort",
                "intrinsicYieldLong",
                "intrinsicYieldShort",
                "totalDepositsUsdLong",
                "totalDepositsUsdShort",
                "totalDebtUsdLong",
                "totalDebtUsdShort",
                "totalLiquidityUsdLong",
                "totalLiquidityUsdShort",
                "borrowLiquidityShort"
              ],
              "default": "aprTotal"
            },
            "description": "Sort field"
          },
          {
            "name": "sortDir",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ASC",
                "DESC"
              ],
              "default": "DESC"
            },
            "description": "Sort direction"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated leverage pairs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LeveragePairsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "start": 1,
                    "count": 1,
                    "items": [
                      {
                        "chainId": "1",
                        "lender": "AAVE_V3",
                        "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",
                        "collateralFactorLong": 0.94,
                        "borrowCollateralFactorLong": 0.92,
                        "borrowFactorLong": 1,
                        "collateralDisabledLong": true,
                        "debtDisabledLong": true,
                        "collateralFactorShort": 0.94,
                        "borrowCollateralFactorShort": 0.92,
                        "borrowFactorShort": 1,
                        "collateralDisabledShort": true,
                        "debtDisabledShort": true,
                        "eModeConfigId": "string",
                        "eMode": "string",
                        "aprBase": 1,
                        "aprTotal": 1,
                        "maxLeverage": 1,
                        "ltv": 1,
                        "depositRateLong": 1,
                        "variableBorrowRateShort": 1,
                        "intrinsicYieldLong": 1,
                        "intrinsicYieldShort": 1,
                        "variableBorrowDisabledShort": true,
                        "termsShort": [
                          {
                            "termId": 2,
                            "depositApr": 1,
                            "available": 1,
                            "durationDays": 7,
                            "durationSecs": 604800,
                            "apr": 3.85,
                            "aprAtAmount": 1,
                            "fillable": 1,
                            "capped": true,
                            "ladder": [
                              {
                                "apr": 1,
                                "units": "string",
                                "assets": 1
                              }
                            ]
                          }
                        ],
                        "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"
                          }
                        },
                        "rewardAprLong": 1,
                        "rewardAprShort": 1,
                        "rewardsLong": [
                          {}
                        ],
                        "rewardsShort": [
                          {}
                        ],
                        "totalDepositsLong": 1,
                        "totalDebtLong": 1,
                        "totalLiquidityLong": 1,
                        "totalDepositsShort": 1,
                        "totalDebtShort": 1,
                        "totalLiquidityShort": 1,
                        "totalDepositsUsdLong": 1,
                        "totalDebtUsdLong": 1,
                        "totalLiquidityUsdLong": 1,
                        "totalDepositsUsdShort": 1,
                        "totalDebtUsdShort": 1,
                        "totalLiquidityUsdShort": 1,
                        "borrowLiquidityShort": 1,
                        "withdrawLiquidityLong": 1,
                        "depositableLong": 1,
                        "utilizationLong": 1,
                        "utilizationShort": 1,
                        "underlyingInfoLong": {
                          "asset": {},
                          "prices": {},
                          "oraclePrice": {}
                        },
                        "underlyingInfoShort": {
                          "asset": {},
                          "prices": {},
                          "oraclePrice": {}
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "browse-all-leverage-pairs"
      }
    },
    "/v1/data/lending/pairs/optimize": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Collateral ⇄ debt optimizer",
        "description": "Filter pairs by either or both sides, then optionally compute the opposite-side amount per row.\n\n## Asset selection\n`collaterals` / `debts` are reinterpreted by chain mode:\n- **Single chain** (`chainId`): values are token addresses.\n- **Multi-chain or no chain**: values are asset groups.\n\nUse `collateralGroups` / `debtGroups` to force group semantics in any chain mode.\nGroup params and address params on the same side are OR'd.\n\n### The native asset, and why you usually want groups\nThe 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.\n\nNative 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.\n\n## Amount params\nThe collateral and debt sides are **independent** — supply an amount on either side, both, or neither:\n- `collateralAmount` (token units; requires exactly one collateral asset)\n- `collateralAmountUsd` (USD; multi-asset OK)\n- `debtAmount` (token units; requires exactly one debt asset)\n- `debtAmountUsd` (USD; multi-asset OK)\n\nA 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).\nUn-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.\n\n## Depth-aware APR\nWhenever 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.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/pairs/optimize`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `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. |\n| `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. |\n| `lender` | query | string | no | Single lender key See the `LenderId` schema for the full set of accepted values. |\n| `lenders` | query | string | no | CSV of lender keys (prefix-expanded) See the `LenderId` schema for the full set of accepted values. |\n| `excludeLenders` | query | string | no | CSV of lender keys to exclude (prefix-expanded) |\n| `collaterals` | query | string | no | CSV of long-side filters. Token addresses (single chain) or asset groups (multi/no chain). |\n| `debts` | query | string | no | CSV of short-side filters. Same dual semantics as `collaterals`. |\n| `collateralGroups` | query | string | no | CSV of long-side asset groups (works in any chain mode). |\n| `debtGroups` | query | string | no | CSV of short-side asset groups (works in any chain mode). |\n| `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. |\n| `collateralTagsMode` | query | `any`, `all` | no | How to match multiple `collateralTags`: `any` (has at least one) or `all` (has every one). |\n| `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. |\n| `debtTagsMode` | query | `any`, `all` | no | How to match multiple `debtTags`: `any` or `all`. |\n| `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`). |\n| `collateralAmount` | query | number | no | Token-unit collateral amount. Requires exactly one collateral asset. |\n| `collateralAmountUsd` | query | number | no | USD collateral amount. Multi-asset selections OK. |\n| `debtAmount` | query | number | no | Token-unit debt amount. Requires exactly one debt asset. |\n| `debtAmountUsd` | query | number | no | USD debt amount. Multi-asset selections OK. |\n| `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. |\n| `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. |\n| `minApr` | query | number | no | Minimum total APR |\n| `maxApr` | query | number | no | Maximum total APR |\n| `minLeverage` | query | number | no | Minimum leverage |\n| `minDepositApr` | query | number | no | Min deposit APR including intrinsic yield (long side) |\n| `maxBorrowRate` | query | number | no | Max borrow rate including intrinsic yield (short side) |\n| `minLtv` | query | number | no | Minimum LTV (0-1) |\n| `maxUtilizationLong` | query | number | no | Max collateral-side utilization (0-1) |\n| `maxUtilizationShort` | query | number | no | Max debt-side utilization (0-1) |\n| `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`). |\n| `minBorrowLiquidityUsd` | query | number | no | Min debt-side borrow liquidity USD |\n| `minDepositsUsdLong` | query | number | no | Min collateral-side deposits USD |\n| `minDebtUsdShort` | query | number | no | Min debt-side total debt USD |\n| `maxRiskScore` | query | number | no | Backwards-compat alias for `maxConfigRiskScore` |\n| `maxConfigRiskScore` | query | number | no | Max config risk score |\n| `maxTokenRiskScore` | query | number | no | Max token risk score |\n| `maxChainRiskScore` | query | number | no | Max chain risk score |\n| `maxLenderRiskScore` | query | number | no | Max lender risk score |\n| `start` | query | integer | no | Pagination offset |\n| `count` | query | integer | no | Page size (max 100) |\n| `sortBy` | query | `aprTotal`, `aprBase`, `maxLeverage`, `ltv`, `depositAprLong`, `borrowAprShort`, … (15 values) | no | Sort field |\n| `sortDir` | query | `ASC`, `DESC` | no | Sort direction |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainIds` | string[] | EVM chain ids, as decimal strings. See the `ChainId` schema. |\n| `data.collaterals` | string[] |  |\n| `data.debts` | string[] |  |\n| `data.collateralAmount` | number |  |\n| `data.collateralAmountUsd` | number |  |\n| `data.debtAmount` | number |  |\n| `data.debtAmountUsd` | number |  |\n| `data.start` | integer |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `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. |\n| `data.items[].marketLongUid` | string | Market UID of the collateral side |\n| `data.items[].marketShortUid` | string | Market UID of the debt side |\n| `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. |\n| `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. |\n| `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. |\n| `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data.items[].assetLong` | string |  |\n| `data.items[].assetShort` | string |  |\n| `data.items[].assetGroupLong` | string |  |\n| `data.items[].assetGroupShort` | string |  |\n| `data.items[].symbolLong` | string | Collateral token symbol |\n| `data.items[].nameLong` | string | Collateral token name |\n| `data.items[].symbolShort` | string | Debt token symbol |\n| `data.items[].nameShort` | string | Debt token name |\n| `data.items[].aprBase` | number | Leverage-weighted net APR % EXCLUDING rewards — the SUSTAINABLE rate (reward incentives are typically transient). |\n| `data.items[].aprTotal` | number | Leverage-weighted net APR % INCLUDING rewards. The reward contribution is aprTotal − aprBase. |\n| `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data.items[].ltv` | number | Loan-to-value ratio, as a fraction between 0 and 1. |\n| `data.items[].depositAprLong` | number | Effective deposit APR (depositRate + intrinsicYield) |\n| `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). |\n| `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. |\n| `data.items[].totalDepositsUsdLong` | number |  |\n| `data.items[].totalDepositsUsdShort` | number |  |\n| `data.items[].totalDebtUsdLong` | number |  |\n| `data.items[].totalDebtUsdShort` | number |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainIds\": [\n      \"1\"\n    ],\n    \"collaterals\": [\n      \"string\"\n    ],\n    \"debts\": [\n      \"string\"\n    ],\n    \"collateralAmount\": 1.0,\n    \"collateralAmountUsd\": 1.0,\n    \"debtAmount\": 1.0,\n    \"debtAmountUsd\": 1.0,\n    \"start\": 1,\n    \"count\": 1,\n    \"items\": [\n      {\n        \"chainId\": \"1\",\n        \"lender\": \"AAVE_V3\",\n        \"fixedTerm\": {\n          \"model\": \"term\",\n          \"maturity\": 1,\n          \"fees\": {},\n          \"earlyRepay\": {},\n          \"provider\": {},\n          \"auction\": {\n            \"status\": \"open\",\n            \"canBorrow\": true,\n            \"canLend\": true,\n            \"secondsUntilClose\": 263000,\n            \"implications\": [\n              \"string\"\n            ],\n            \"id\": \"string\",\n            \"startTime\": 1,\n            \"revealTime\": 1,\n            \"endTime\": 1,\n            \"minBorrowAmount\": \"1000000000\",\n            \"minLendAmount\": \"1000000000\"\n          }\n        },\n        \"marketLongUid\": \"string\",\n        \"marketShortUid\": \"string\",\n        \"marketNameLong\": \"string\",\n        \"marketNameShort\": \"string\",\n        \"curatorNameLong\": \"string\",\n        \"curatorNameShort\": \"string\",\n        \"assetLong\": \"string\",\n        \"assetShort\": \"string\",\n        \"assetGroupLong\": \"string\",\n        \"assetGroupShort\": \"string\",\n        \"symbolLong\": \"string\",\n        \"nameLong\": \"string\",\n        \"symbolShort\": \"string\",\n        \"nameShort\": \"string\",\n        \"aprBase\": 1.0,\n        \"aprTotal\": 1.0,\n        \"maxLeverage\": 1.0,\n        \"ltv\": 1.0,\n        \"depositAprLong\": 1.0,\n        \"borrowAprShort\": 1.0,\n        \"originationFeeShort\": 1.0,\n        \"totalDepositsUsdLong\": 1.0,\n        \"totalDepositsUsdShort\": 1.0,\n        \"totalDebtUsdLong\": 1.0,\n        \"totalDebtUsdShort\": 1.0,\n        \"totalLiquidityUsdLong\": 1.0,\n        \"totalLiquidityUsdShort\": 1.0,\n        \"borrowLiquidityShort\": 1.0,\n        \"utilizationLong\": 1.0,\n        \"utilizationShort\": 1.0,\n        \"maxDebtAmount\": 1.0,\n        \"maxDebtAmountUsd\": 1.0,\n        \"minCollateralAmount\": 1.0,\n        \"minCollateralAmountUsd\": 1.0,\n        \"borrowAprAtAmount\": 1.0,\n        \"depositAprAtAmount\": 1.0,\n        \"netAprAtAmount\": 1.0,\n        \"netAprAtAmountBase\": 1.0,\n        \"borrowDepthShort\": {},\n        \"supplyDepthLong\": {},\n        \"risk\": {\n          \"maxTokenScore\": 1,\n          \"breakdown\": [\n            {\n              \"category\": \"lender\",\n              \"score\": 1,\n              \"label\": \"low\",\n              \"curatorIds\": [\n                \"string\"\n              ]\n            }\n          ]\n        }\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Single chain ID. When set, asset filters operate on token addresses. See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "chainIds",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,10,8453"
            },
            "description": "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.",
            "example": "1,10,8453"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Single lender key See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "lenders",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3,AAVE_V4,SPARK"
            },
            "description": "CSV of lender keys (prefix-expanded) See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3,AAVE_V4,SPARK"
          },
          {
            "name": "excludeLenders",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CSV of lender keys to exclude (prefix-expanded)"
          },
          {
            "name": "collaterals",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "WETH,wstETH"
            },
            "description": "CSV of long-side filters. Token addresses (single chain) or asset groups (multi/no chain).",
            "example": "WETH,wstETH"
          },
          {
            "name": "debts",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CSV of short-side filters. Same dual semantics as `collaterals`."
          },
          {
            "name": "collateralGroups",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC,USDT,DAI"
            },
            "description": "CSV of long-side asset groups (works in any chain mode).",
            "example": "USDC,USDT,DAI"
          },
          {
            "name": "debtGroups",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CSV of short-side asset groups (works in any chain mode)."
          },
          {
            "name": "collateralTags",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "lst"
            },
            "description": "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.",
            "example": "lst"
          },
          {
            "name": "collateralTagsMode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "any",
                "all"
              ],
              "default": "any"
            },
            "description": "How to match multiple `collateralTags`: `any` (has at least one) or `all` (has every one)."
          },
          {
            "name": "debtTags",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "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."
          },
          {
            "name": "debtTagsMode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "any",
                "all"
              ],
              "default": "any"
            },
            "description": "How to match multiple `debtTags`: `any` or `all`."
          },
          {
            "name": "includeExpired",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include pairs whose collateral or debt is an expired Pendle PT. Excluded by default (judged live off `props.pendle.expiry`/`expired`)."
          },
          {
            "name": "collateralAmount",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Token-unit collateral amount. Requires exactly one collateral asset."
          },
          {
            "name": "collateralAmountUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "USD collateral amount. Multi-asset selections OK."
          },
          {
            "name": "debtAmount",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Token-unit debt amount. Requires exactly one debt asset."
          },
          {
            "name": "debtAmountUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "USD debt amount. Multi-asset selections OK."
          },
          {
            "name": "depth",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "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."
          },
          {
            "name": "includeIlliquid",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "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."
          },
          {
            "name": "minApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum total APR"
          },
          {
            "name": "maxApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum total APR"
          },
          {
            "name": "minLeverage",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum leverage"
          },
          {
            "name": "minDepositApr",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min deposit APR including intrinsic yield (long side)"
          },
          {
            "name": "maxBorrowRate",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max borrow rate including intrinsic yield (short side)"
          },
          {
            "name": "minLtv",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum LTV (0-1)"
          },
          {
            "name": "maxUtilizationLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max collateral-side utilization (0-1)"
          },
          {
            "name": "maxUtilizationShort",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max debt-side utilization (0-1)"
          },
          {
            "name": "minLiquidityUsdLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — capacity is gated separately (see `includeIlliquid`)."
          },
          {
            "name": "minBorrowLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min debt-side borrow liquidity USD"
          },
          {
            "name": "minDepositsUsdLong",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min collateral-side deposits USD"
          },
          {
            "name": "minDebtUsdShort",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Min debt-side total debt USD"
          },
          {
            "name": "maxRiskScore",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 4
            },
            "description": "Backwards-compat alias for `maxConfigRiskScore`"
          },
          {
            "name": "maxConfigRiskScore",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 4
            },
            "description": "Max config risk score"
          },
          {
            "name": "maxTokenRiskScore",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max token risk score"
          },
          {
            "name": "maxChainRiskScore",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max chain risk score"
          },
          {
            "name": "maxLenderRiskScore",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Max lender risk score"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Pagination offset"
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size (max 100)"
          },
          {
            "name": "sortBy",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "aprTotal",
                "aprBase",
                "maxLeverage",
                "ltv",
                "depositAprLong",
                "borrowAprShort",
                "totalDepositsUsdLong",
                "totalDepositsUsdShort",
                "totalDebtUsdLong",
                "totalDebtUsdShort",
                "totalLiquidityUsdLong",
                "totalLiquidityUsdShort",
                "utilizationLong",
                "utilizationShort",
                "borrowLiquidityShort"
              ],
              "default": "aprTotal"
            },
            "description": "Sort field"
          },
          {
            "name": "sortDir",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ASC",
                "DESC"
              ],
              "default": "DESC"
            },
            "description": "Sort direction"
          }
        ],
        "responses": {
          "200": {
            "description": "Optimizer pairs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/OptimizerPairsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "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"
                              ]
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "collateral-to-debt-optimizer"
      }
    },
    "/v1/data/lending/comparables": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Comparable rates for one pair",
        "description": "The **N best comparable rates for a single pair**, priced at the caller’s size and holding period. One round-trip, small payload — built to sit behind a rate pill next to a borrow input.\n\nUnlike `/pairs/optimize` (rank every leveraged pair), this answers the question a borrow form asks: *I am about to borrow X of asset D against collateral C — what are the best rates for that same trade, at my size, over my horizon?*\n\n## Three rates, deliberately kept apart\n- `aprPct` — what the venue advertises: spot at 0 notional, or top of book.\n- `aprAtAmountPct` — the same rate at **your size**. A utilization pool re-prices its whole balance to the post-borrow rate (marginal == average); an order book fills cheapest-first, so this is the VWAP of the tiers consumed. Null without an amount.\n- `effectiveAprPct` — the size-priced rate normalized to `horizonDays`. **This is what `rank` sorts on.**\n\n## Horizon normalization\nA 4-week fixed rate and a floating pool are not comparable until both are priced over the same holding period. Each venue supplies a repayment rule: a Lista loan exited early pays roughly half the remaining term’s interest (`r·(T+h)/(2h)` — 1%/1yr exited at 6 months is **1.5% effective**); Midnight/Term charge no penalty but exiting means a resale at the then-current price (`horizon.priceRisk`); Exactly rebates unassigned earnings; a CDP’s one-time origination fee amortizes over the horizon, so it dominates on short holds. A horizon that outlasts the term assumes a roll at today’s rate and reports `locked: false`.\nAlways render `horizon.locked` and `horizon.assumptions` next to the number — a normalized rate is not a contractual one.\n\n## Obtainability is part of the answer\nTerm Finance originates only inside periodic sealed-bid rounds; between rounds its rate card still quotes the LAST round’s clearing rate — real, but not takeable. Those rows are dropped by default and, with `includeUnobtainable=true`, returned flagged (`obtainable: false`, `quoteBasis: \"last-clearing\"`) and ranked last. A venue that cannot fund the requested size is marked `depth.capped` and demoted rather than ranked on a rate it can’t honour.\n\n## Comparability filters (what makes this a comparison rather than a list)\n**Depth band** — `floor = min(minLiquidityRatio × anchor, liquidityFloorCapUsd)`, default `min(50% × anchor, $10M)`. A venue an order of magnitude shallower is a different product, and it is exactly those markets that quote absurd rates — a near-empty isolated market with reward emissions prices borrowing at **−25%**, a real number and a useless comparison against a $5B pool. The cap is not optional: a pure ratio breaks on the biggest pairs, where half of a $5B pool is a $2.5B floor nothing clears, so the comparison would come back empty exactly where alternatives matter most. The anchor is `referenceMarketUid`'s own depth when given, else the deepest candidate. `droppedIlliquid` + `liquidityFloorUsd` report it — the filter is never silent; `minLiquidityUsd` replaces the formula and `includeIlliquid=true` turns it off.\n**Stale venues.** A lender whose ingest lagged past the freshness window drops out of the underlying pairs view — which reads exactly like \"that lender doesn't offer this pair\". Those rows are excluded from ranking but **counted** (`droppedStale`, `staleMaxHours`), because a $19B deployment vanishing with no signal is worse than a short list. `includeStale=true` ranks them anyway.\n**One collateral basis.** When the caller pins no collateral (a standalone borrow form knows none), comparing \"borrow USDC\" across every collateral in existence is not a comparison. The server picks ONE representative collateral per chain — first hit in `collateralPreference` (default `ETH,BTC,USDC,USDT`), else the collateral group backing the deepest markets, which resolves to the wrapped native where neither is listed — and compares only venues backed by it. The choice comes back as `collateralBasis` (e.g. `{\"1\":\"ETH\"}`) so the UI can say *\"vs WETH-backed\"*. An explicit `collateral`/`collateralGroups` always wins and disables this.\n\n## Rewards\nThe headline rate folds in reward emissions (same composition as `/pairs/optimize`), which is why a borrow rate can be **negative**. That is real but transient, so each row also carries `rewardAprPct` and `aprExRewardsPct` — the structural cost without emissions. Ranking stays on the headline; showing both is the caller's job.\n\n## Ranking\n`obtainable` first, then non-`capped`, then best `effectiveAprPct` (cheapest for a borrow, highest for a supply), then deepest liquidity as tie-break. Results are deduped to one row per `(chain, lender, market, term)` — the pairs view is combinatorial in the other leg, so without it the \"5 best rates\" would be five copies of the same market.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/comparables`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Single chain ID. When set, asset filters operate on token addresses. Pass one for an actionable list — cross-chain rows are a comparison, not one executable position. See the `ChainId` schema for the full set of supported chains. |\n| `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. |\n| `side` | query | `borrow`, `supply` | no | Which leg to compare. |\n| `debt` | query | string | no | The borrowed asset — address (single chain) or asset group. Required for `side=borrow`. Aliases: `debts`, `debtGroups`. |\n| `debtGroups` | query | string | no | CSV of debt-side asset groups (works in any chain mode). |\n| `collateral` | query | string | no | The collateral asset. Required for `side=supply`; strongly recommended for `side=borrow` — a market that will not take your collateral is not a comparable. Aliases: `collaterals`, `collateralGroups`. |\n| `collateralGroups` | query | string | no | CSV of collateral-side asset groups (works in any chain mode). |\n| `amount` | query | number | no | Notional in TOKEN UNITS of the priced leg (the debt asset for a borrow). Requires exactly one asset on that side. |\n| `amountUsd` | query | number | no | Same notional in USD. Works with multi-asset selections. Mutually exclusive with `amount`. |\n| `horizonDays` | query | number | no | Holding period every venue is repriced to. At 365 a floating pool’s effective rate equals its sticker rate. |\n| `rateType` | query | `all`, `fixed`, `float` | no | Post-filter applied before dedupe and ranking. |\n| `limit` | query | integer | no | How many comparables to return (max 25). |\n| `referenceMarketUid` | query | string | no | The venue the caller is already on. Returned as `reference` and excluded from `items`, so the pill can render \"you: X% · best: Y%\". |\n| `referenceTermId` | query | string | no | Disambiguates which term of the reference market is the caller’s own. |\n| `includeUnobtainable` | query | boolean | no | Keep quotes that cannot be taken right now (closed Term auction rounds), flagged and ranked last. |\n| `minLiquidityRatio` | query | number | no | Ratio side of the depth floor `min(ratio × anchor, cap)`. |\n| `liquidityFloorCapUsd` | query | number | no | Cap side of the depth floor — stops a huge anchor from demanding a comparably huge venue and returning nothing. |\n| `minLiquidityUsd` | query | number | no | Absolute USD depth floor that REPLACES the computed `min(ratio × anchor, cap)`. |\n| `includeStale` | query | boolean | no | Rank venues whose market data is older than the freshness window. Excluded but counted (`droppedStale`) by default. |\n| `includeIlliquid` | query | boolean | no | Disable the depth band entirely and rank every venue regardless of size. |\n| `collateralPreference` | query | string | no | CSV of collateral asset groups tried in order when picking the comparison basis (only used when no collateral is pinned). |\n| `lenders` | query | string | no | CSV of lender keys (prefix-expanded) to restrict the comparison to. See the `LenderId` schema for the full set of accepted values. |\n| `excludeLenders` | query | string | no | CSV of lender keys to exclude (prefix-expanded). |\n| `maxConfigRiskScore` | query | number | no | Config-risk ceiling (default 4, as on the pair endpoints). |\n| `maxTokenRiskScore` | query | number | no | Token-risk ceiling across both legs. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.side` | `borrow`, `supply` |  |\n| `data.horizonDays` | number |  |\n| `data.amount` | number |  |\n| `data.amountUsd` | number |  |\n| `data.chainIds` | string[] | EVM chain ids, as decimal strings. See the `ChainId` schema. |\n| `data.scanned` | integer | Pair rows considered before ranking. |\n| `data.truncated` | boolean | The candidate guard cap bound, so ranking saw only the deepest rows — narrow the filter. Never a silent trim. |\n| `data.available` | integer | Distinct comparables that existed before `limit` was applied. |\n| `data.liquidityFloorUsd` | number | Venues below this USD depth were dropped as not comparable (0 = no floor applied). |\n| `data.droppedIlliquid` | integer | How many venues the depth band removed. An opinionated filter must never be silent — surface this rather than implying nothing else exists. |\n| `data.droppedStale` | integer | Venues excluded because their market data is older than `staleMaxHours` — an ingest lag, not an absent lender. Non-zero is the difference between \"no one else offers this pair\" and \"we cannot currently see who does\". `includeStale=true` ranks them anyway. |\n| `data.staleMaxHours` | number | The freshness window `droppedStale` was measured against. |\n| `data.collateralBasis` | object | The single collateral group each chain's rows were compared against when the caller pinned none, e.g. `{\"1\":\"ETH\"}`. Empty when a collateral was supplied, or on the supply side. |\n| `data.reference` | object | The venue the caller is already on (`referenceMarketUid`), pulled out of `items` so the UI can render \"you: X% · best: Y%\". |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].rank` | integer | 1-based position in the ranking. `0` on the `reference` item. |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].lender` | string | Raw lender key — stable, use it for keying and deeplinks. Per-market lenders (Morpho Blue, Silo, Euler) encode a hashed market id here, so it is NOT presentable. |\n| `data.items[].lenderName` | string | Display name from the lender registry, falling back to the raw key when none is registered. This is what a UI should render. |\n| `data.items[].lenderLogoUri` | string |  |\n| `data.items[].marketUid` | string | The market the rate belongs to: the debt market for a borrow quote, the collateral market for a supply quote. |\n| `data.items[].marketName` | string |  |\n| `data.items[].curatorName` | string |  |\n| `data.items[].eMode` | string |  |\n| `data.items[].rateType` | `fixed`, `float` |  |\n| `data.items[].rateModel` | `variable`, `lista`, `midnight`, `term`, `exactly`, `teller`, … (9 values) | Which repayment rule priced this quote. |\n| `data.items[].aprPct` | number | Sticker rate, APR %. Includes intrinsic yield and reward APR (same composition as `borrowAprShort` / `depositAprLong`); a one-time origination fee is NOT in it — the horizon model amortizes that separately. |\n| `data.items[].aprAtAmountPct` | number | The rate at the requested size. Null when no amount was supplied. A utilization pool re-prices its whole balance to the post-action rate; an order book fills cheapest-first, so this is the VWAP of the tiers consumed. |\n| `data.items[].rewardAprPct` | number | Reward emissions folded into the headline (positive = subsidising a borrow). Large emissions can push a borrow rate NEGATIVE. |\n| `data.items[].aprExRewardsPct` | number | The rate WITHOUT reward emissions — the structural, sustainable cost. Show it next to a reward-inflated headline; emissions are transient. |\n| `data.items[].effectiveAprPct` | number | Size-priced rate normalized to `horizonDays`. The ranking number. |\n| `data.items[].costPct` | number | Total cost over the horizon as a percent of principal. |\n| `data.items[].horizon` | object | How the effective rate was arrived at — the caveats a UI must show next to a normalized number. |\n| `data.items[].horizon.basis` | `flat-forward`, `early-exit`, `held-to-maturity`, `rolled` | `flat-forward`: no maturity, today’s floating rate assumed to hold. `early-exit`: horizon shorter than the term, the venue’s exit rule applied. `held-to-maturity`: horizon matches the term (the clean case). `rolled`: horizon outlasts the term, a roll at today’s rate assumed. |\n| `data.items[].horizon.locked` | boolean | Is the rate contractually fixed for the WHOLE horizon? False for floating pools and for a fixed term that has to be rolled to cover the horizon. |\n| `data.items[].horizon.priceRisk` | boolean | Exiting early means unwinding on an order book at the then-current price (Midnight/Term), so the realized cost can land either side of the quote. Not priced in — flagged. |\n| `data.items[].horizon.assumptions` | string[] | Display-ready caveats, most important first. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"side\": \"borrow\",\n    \"horizonDays\": 1.0,\n    \"amount\": 1.0,\n    \"amountUsd\": 1.0,\n    \"chainIds\": [\n      \"1\"\n    ],\n    \"scanned\": 1,\n    \"truncated\": true,\n    \"available\": 1,\n    \"liquidityFloorUsd\": 1.0,\n    \"droppedIlliquid\": 1,\n    \"droppedStale\": 1,\n    \"staleMaxHours\": 1.0,\n    \"collateralBasis\": {},\n    \"reference\": {\n      \"rank\": 1,\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"lenderName\": \"AAVE_V3\",\n      \"lenderLogoUri\": \"AAVE_V3\",\n      \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n      \"marketName\": \"string\",\n      \"curatorName\": \"string\",\n      \"eMode\": \"string\",\n      \"rateType\": \"fixed\",\n      \"rateModel\": \"variable\",\n      \"aprPct\": 1.0,\n      \"aprAtAmountPct\": 1.0,\n      \"rewardAprPct\": 1.0,\n      \"aprExRewardsPct\": 1.0,\n      \"effectiveAprPct\": 1.0,\n      \"costPct\": 1.0,\n      \"horizon\": {\n        \"basis\": \"flat-forward\",\n        \"locked\": true,\n        \"priceRisk\": true,\n        \"assumptions\": [\n          \"string\"\n        ]\n      },\n      \"termId\": \"string\",\n      \"durationDays\": 1.0,\n      \"maturity\": 1.0,\n      \"termDays\": 1.0,\n      \"obtainable\": true,\n      \"obtainableReason\": \"string\",\n      \"quoteBasis\": \"live\",\n      \"depth\": {\n        \"fillable\": 1.0,\n        \"capped\": true,\n        \"liquidityUsd\": 1.0,\n        \"utilization\": 1.0\n      },\n      \"collateral\": {\n        \"address\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"assetGroup\": \"string\",\n        \"symbol\": \"string\",\n        \"decimals\": 1.0,\n        \"logoUri\": \"string\",\n        \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      },\n      \"debt\": {\n        \"address\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"assetGroup\": \"string\",\n        \"symbol\": \"string\",\n        \"decimals\": 1.0,\n        \"logoUri\": \"string\",\n        \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      },\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"risk\": {\n        \"configScore\": 1.0,\n        \"maxTokenScore\": 1.0\n      }\n    },\n    \"count\": 1,\n    \"items\": [\n      {\n        \"rank\": 1,\n        \"chainId\": \"1\",\n        \"lender\": \"AAVE_V3\",\n        \"lenderName\": \"AAVE_V3\",\n        \"lenderLogoUri\": \"AAVE_V3\",\n        \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"marketName\": \"string\",\n        \"curatorName\": \"string\",\n        \"eMode\": \"string\",\n        \"rateType\": \"fixed\",\n        \"rateModel\": \"variable\",\n        \"aprPct\": 1.0,\n        \"aprAtAmountPct\": 1.0,\n        \"rewardAprPct\": 1.0,\n        \"aprExRewardsPct\": 1.0,\n        \"effectiveAprPct\": 1.0,\n        \"costPct\": 1.0,\n        \"horizon\": {\n          \"basis\": \"flat-forward\",\n          \"locked\": true,\n          \"priceRisk\": true,\n          \"assumptions\": [\n            \"string\"\n          ]\n        },\n        \"termId\": \"string\",\n        \"durationDays\": 1.0,\n        \"maturity\": 1.0,\n        \"termDays\": 1.0,\n        \"obtainable\": true,\n        \"obtainableReason\": \"string\",\n        \"quoteBasis\": \"live\",\n        \"depth\": {\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"liquidityUsd\": 1.0,\n          \"utilization\": 1.0\n        },\n        \"collateral\": {\n          \"address\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n          \"assetGroup\": \"string\",\n          \"symbol\": \"string\",\n          \"decimals\": 1.0,\n          \"logoUri\": \"string\",\n          \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n        },\n        \"debt\": {\n          \"address\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n          \"assetGroup\": \"string\",\n          \"symbol\": \"string\",\n          \"decimals\": 1.0,\n          \"logoUri\": \"string\",\n          \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n        },\n        \"maxLeverage\": 1.0,\n        \"ltv\": 1.0,\n        \"risk\": {\n          \"configScore\": 1.0,\n          \"maxTokenScore\": 1.0\n        }\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "8453"
            },
            "description": "Single chain ID. When set, asset filters operate on token addresses. Pass one for an actionable list — cross-chain rows are a comparison, not one executable position. See the `ChainId` schema for the full set of supported chains.",
            "example": "8453"
          },
          {
            "name": "chainIds",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "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."
          },
          {
            "name": "side",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "borrow",
                "supply"
              ],
              "default": "borrow"
            },
            "description": "Which leg to compare."
          },
          {
            "name": "debt",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The borrowed asset — address (single chain) or asset group. Required for `side=borrow`. Aliases: `debts`, `debtGroups`."
          },
          {
            "name": "debtGroups",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC"
            },
            "description": "CSV of debt-side asset groups (works in any chain mode).",
            "example": "USDC"
          },
          {
            "name": "collateral",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The collateral asset. Required for `side=supply`; strongly recommended for `side=borrow` — a market that will not take your collateral is not a comparable. Aliases: `collaterals`, `collateralGroups`."
          },
          {
            "name": "collateralGroups",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "CBBTC"
            },
            "description": "CSV of collateral-side asset groups (works in any chain mode).",
            "example": "CBBTC"
          },
          {
            "name": "amount",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Notional in TOKEN UNITS of the priced leg (the debt asset for a borrow). Requires exactly one asset on that side."
          },
          {
            "name": "amountUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Same notional in USD. Works with multi-asset selections. Mutually exclusive with `amount`."
          },
          {
            "name": "horizonDays",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 365
            },
            "description": "Holding period every venue is repriced to. At 365 a floating pool’s effective rate equals its sticker rate."
          },
          {
            "name": "rateType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "fixed",
                "float"
              ],
              "default": "all"
            },
            "description": "Post-filter applied before dedupe and ranking."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5
            },
            "description": "How many comparables to return (max 25)."
          },
          {
            "name": "referenceMarketUid",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The venue the caller is already on. Returned as `reference` and excluded from `items`, so the pill can render \"you: X% · best: Y%\"."
          },
          {
            "name": "referenceTermId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Disambiguates which term of the reference market is the caller’s own."
          },
          {
            "name": "includeUnobtainable",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Keep quotes that cannot be taken right now (closed Term auction rounds), flagged and ranked last."
          },
          {
            "name": "minLiquidityRatio",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0.5
            },
            "description": "Ratio side of the depth floor `min(ratio × anchor, cap)`."
          },
          {
            "name": "liquidityFloorCapUsd",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 10000000
            },
            "description": "Cap side of the depth floor — stops a huge anchor from demanding a comparably huge venue and returning nothing."
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Absolute USD depth floor that REPLACES the computed `min(ratio × anchor, cap)`."
          },
          {
            "name": "includeStale",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Rank venues whose market data is older than the freshness window. Excluded but counted (`droppedStale`) by default."
          },
          {
            "name": "includeIlliquid",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Disable the depth band entirely and rank every venue regardless of size."
          },
          {
            "name": "collateralPreference",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "ETH,BTC,USDC,USDT"
            },
            "description": "CSV of collateral asset groups tried in order when picking the comparison basis (only used when no collateral is pinned).",
            "example": "ETH,BTC,USDC,USDT"
          },
          {
            "name": "lenders",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CSV of lender keys (prefix-expanded) to restrict the comparison to. See the `LenderId` schema for the full set of accepted values."
          },
          {
            "name": "excludeLenders",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "CSV of lender keys to exclude (prefix-expanded)."
          },
          {
            "name": "maxConfigRiskScore",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Config-risk ceiling (default 4, as on the pair endpoints)."
          },
          {
            "name": "maxTokenRiskScore",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Token-risk ceiling across both legs."
          }
        ],
        "responses": {
          "200": {
            "description": "Comparable rates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/ComparableRatesResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "side": "borrow",
                    "horizonDays": 1,
                    "amount": 1,
                    "amountUsd": 1,
                    "chainIds": [
                      "1"
                    ],
                    "scanned": 1,
                    "truncated": true,
                    "available": 1,
                    "liquidityFloorUsd": 1,
                    "droppedIlliquid": 1,
                    "droppedStale": 1,
                    "staleMaxHours": 1,
                    "collateralBasis": {},
                    "reference": {
                      "rank": 1,
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "lenderName": "AAVE_V3",
                      "lenderLogoUri": "AAVE_V3",
                      "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                      "marketName": "string",
                      "curatorName": "string",
                      "eMode": "string",
                      "rateType": "fixed",
                      "rateModel": "variable",
                      "aprPct": 1,
                      "aprAtAmountPct": 1,
                      "rewardAprPct": 1,
                      "aprExRewardsPct": 1,
                      "effectiveAprPct": 1,
                      "costPct": 1,
                      "horizon": {
                        "basis": "flat-forward",
                        "locked": true,
                        "priceRisk": true,
                        "assumptions": [
                          "string"
                        ]
                      },
                      "termId": "string",
                      "durationDays": 1,
                      "maturity": 1,
                      "termDays": 1,
                      "obtainable": true,
                      "obtainableReason": "string",
                      "quoteBasis": "live",
                      "depth": {
                        "fillable": 1,
                        "capped": true,
                        "liquidityUsd": 1,
                        "utilization": 1
                      },
                      "collateral": {
                        "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "assetGroup": "string",
                        "symbol": "string",
                        "decimals": 1,
                        "logoUri": "string",
                        "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      },
                      "debt": {
                        "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "assetGroup": "string",
                        "symbol": "string",
                        "decimals": 1,
                        "logoUri": "string",
                        "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      },
                      "maxLeverage": 1,
                      "ltv": 1,
                      "risk": {
                        "configScore": 1,
                        "maxTokenScore": 1
                      }
                    },
                    "count": 1,
                    "items": [
                      {
                        "rank": 1,
                        "chainId": "1",
                        "lender": "AAVE_V3",
                        "lenderName": "AAVE_V3",
                        "lenderLogoUri": "AAVE_V3",
                        "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "marketName": "string",
                        "curatorName": "string",
                        "eMode": "string",
                        "rateType": "fixed",
                        "rateModel": "variable",
                        "aprPct": 1,
                        "aprAtAmountPct": 1,
                        "rewardAprPct": 1,
                        "aprExRewardsPct": 1,
                        "effectiveAprPct": 1,
                        "costPct": 1,
                        "horizon": {
                          "basis": "flat-forward",
                          "locked": true,
                          "priceRisk": true,
                          "assumptions": [
                            "string"
                          ]
                        },
                        "termId": "string",
                        "durationDays": 1,
                        "maturity": 1,
                        "termDays": 1,
                        "obtainable": true,
                        "obtainableReason": "string",
                        "quoteBasis": "live",
                        "depth": {
                          "fillable": 1,
                          "capped": true,
                          "liquidityUsd": 1,
                          "utilization": 1
                        },
                        "collateral": {
                          "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                          "assetGroup": "string",
                          "symbol": "string",
                          "decimals": 1,
                          "logoUri": "string",
                          "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                        },
                        "debt": {
                          "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                          "assetGroup": "string",
                          "symbol": "string",
                          "decimals": 1,
                          "logoUri": "string",
                          "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                        },
                        "maxLeverage": 1,
                        "ltv": 1,
                        "risk": {
                          "configScore": 1,
                          "maxTokenScore": 1
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "comparable-rates-for-one-pair"
      }
    },
    "/v1/data/lending/irm": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "IRM rate curves",
        "description": "Return sampled borrow and deposit rate curves for one or more markets.\n\nEach curve is a series of `(utilization, borrowRate, depositRate)` points spanning\n0% to 100% utilization. Rates are **APR %** (e.g. `5.5` = 5.5% APR).\n\nSupported protocols: `aave`, `aave_v4`, `compound_v2`, `compound_v3`, `morpho` (including Lista), `euler_v2`, `silo`, `fluid`, `gearbox`, `dolomite`.\n\n**Caching:** IRM parameters are quasi-static and cached server-side for 1 hour.\nComputed curves are also cached (keyed by market UIDs + data-point count).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/irm`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUids` | query | string | yes | Comma-separated market UIDs, e.g. `AAVE_V3:1:0xa0b8...` |\n| `dataPoints` | query | integer | no | Number of curve sample points (1–20, default 20) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.count` | integer | Number of markets returned |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].marketUid` | string | Unique market identifier (`lenderKey:chainId:address`) |\n| `data.items[].protocol` | `aave`, `aave_v4`, `compound_v2`, `compound_v3`, `morpho`, `euler_v2`, … (10 values) | IRM model type |\n| `data.items[].lenderKey` | string |  |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].underlyingAddress` | string |  |\n| `data.items[].marketName` | string |  |\n| `data.items[].points` | object[] | Sampled rate curve. Length = dataPoints + 1 (includes u=0 and u=1). |\n| `data.items[].points[].utilization` | number | Utilization ratio (0–1) |\n| `data.items[].points[].borrowRate` | number | Variable borrow rate (APR %, e.g. 7.67 = 7.67%) |\n| `data.items[].points[].depositRate` | number | Deposit/supply rate (APR %, e.g. 3.30 = 3.30%) |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": [\n      {\n        \"marketUid\": \"SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0\",\n        \"protocol\": \"aave\",\n        \"lenderKey\": \"SPARK\",\n        \"chainId\": \"100\",\n        \"underlyingAddress\": \"0x2a22f9c3b484c3629090feed35f17ff8f88f76f0\",\n        \"marketName\": \"Spark USDC.e\",\n        \"points\": [\n          {\n            \"utilization\": 0.95,\n            \"borrowRate\": 7.67,\n            \"depositRate\": 3.3\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0"
            },
            "description": "Comma-separated market UIDs, e.g. `AAVE_V3:1:0xa0b8...`",
            "example": "SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0"
          },
          {
            "name": "dataPoints",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "example": 20
            },
            "description": "Number of curve sample points (1–20, default 20)",
            "example": 20
          }
        ],
        "responses": {
          "200": {
            "description": "Rate curves per market",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "count",
                        "items"
                      ],
                      "properties": {
                        "count": {
                          "type": "integer",
                          "description": "Number of markets returned"
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "marketUid",
                              "protocol",
                              "lenderKey",
                              "chainId",
                              "underlyingAddress",
                              "points"
                            ],
                            "properties": {
                              "marketUid": {
                                "type": "string",
                                "description": "Unique market identifier (`lenderKey:chainId:address`)",
                                "example": "SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0"
                              },
                              "protocol": {
                                "type": "string",
                                "enum": [
                                  "aave",
                                  "aave_v4",
                                  "compound_v2",
                                  "compound_v3",
                                  "morpho",
                                  "euler_v2",
                                  "silo",
                                  "fluid",
                                  "gearbox",
                                  "dolomite"
                                ],
                                "description": "IRM model type"
                              },
                              "lenderKey": {
                                "type": "string",
                                "example": "SPARK"
                              },
                              "chainId": {
                                "type": "string",
                                "example": "100",
                                "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                              },
                              "underlyingAddress": {
                                "type": "string",
                                "example": "0x2a22f9c3b484c3629090feed35f17ff8f88f76f0"
                              },
                              "marketName": {
                                "type": "string",
                                "example": "Spark USDC.e"
                              },
                              "points": {
                                "type": "array",
                                "description": "Sampled rate curve. Length = dataPoints + 1 (includes u=0 and u=1).",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "utilization",
                                    "borrowRate",
                                    "depositRate"
                                  ],
                                  "properties": {
                                    "utilization": {
                                      "type": "number",
                                      "minimum": 0,
                                      "maximum": 1,
                                      "description": "Utilization ratio (0–1)",
                                      "example": 0.95
                                    },
                                    "borrowRate": {
                                      "type": "number",
                                      "description": "Variable borrow rate (APR %, e.g. 7.67 = 7.67%)",
                                      "example": 7.67
                                    },
                                    "depositRate": {
                                      "type": "number",
                                      "description": "Deposit/supply rate (APR %, e.g. 3.30 = 3.30%)",
                                      "example": 3.3
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "description": "The result set for this response."
                        }
                      },
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "marketUid": "SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0",
                        "protocol": "aave",
                        "lenderKey": "SPARK",
                        "chainId": "100",
                        "underlyingAddress": "0x2a22f9c3b484c3629090feed35f17ff8f88f76f0",
                        "marketName": "Spark USDC.e",
                        "points": [
                          {
                            "utilization": 0.95,
                            "borrowRate": 7.67,
                            "depositRate": 3.3
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "irm-rate-curves"
      }
    },
    "/v1/data/lending/irm/depth": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Rate-at-depth (rate vs borrow/supply amount)",
        "description": "Return rate-at-depth data — the amount-axis complement of `/v1/data/lending/irm` (rate vs utilization).\n\nTwo shapes, both optional:\n\n- **grid** (default): a `borrow`/`supply` sweep from 0 to the fillable ceiling — for charts. Disable with `grid=false`.\n- **rateAtAmount**: pass `amount(s)` (token units) and/or `amount(s)Usd` (USD) to get the rate + resulting utilization + fillable ceiling at each specific size — the answer to *\"what rate to borrow X\"*.\n\nFor a utilization pool the whole balance re-prices to one rate, so `rateAtAmount` is the marginal spot rate at the post-action utilization (marginal == average). Order-book venues (Midnight) fill best-first, so their `rateAtAmount` is a **volume-weighted average** over the consumed ladder. Lista's brokered borrow leg is a **flat fixed** rate up to capacity. Rates are **APR %**.\n\n**Caching:** computed grids/points cached server-side for 1 hour (keyed by UIDs + side + points + amounts).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/irm/depth`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUids` | query | string | yes | Comma-separated market UIDs, e.g. `GEARBOX_V3_0x…:9745:0x…` |\n| `side` | query | string | no | `borrow` \\| `supply` \\| `both` (default `borrow`) |\n| `dataPoints` | query | integer | no | Samples per grid (1–60, default 24) |\n| `amounts` | query | string | no | Comma-separated sizes in TOKEN units → adds `rateAtAmount[]`. `amount` is accepted as a singular alias. |\n| `amountsUsd` | query | string | no | Comma-separated sizes in USD (converted per market via its price). `amountUsd` alias accepted. |\n| `grid` | query | string | no | Set `false` to drop the 0→max grid sweep (points-only). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].marketUid` | string | Market identifier, formatted `lender:chainId:address`. |\n| `data.items[].protocol` | string |  |\n| `data.items[].lenderKey` | string |  |\n| `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].underlyingAddress` | string |  |\n| `data.items[].utilization` | number | Current utilization (0–1) |\n| `data.items[].variableBorrowRate` | number | Current 0-notional borrow APR % |\n| `data.items[].borrow` | object | Rate-vs-amount sweep from size 0 to `fillable`. |\n| `data.items[].borrow.side` | `borrow`, `supply` |  |\n| `data.items[].borrow.currentUtilization` | number |  |\n| `data.items[].borrow.currentBorrowAprPct` | number |  |\n| `data.items[].borrow.currentDepositAprPct` | number |  |\n| `data.items[].borrow.fillable` | number | Largest size sampled — the depth ceiling (token units). |\n| `data.items[].borrow.fillableUsd` | number |  |\n| `data.items[].borrow.points` | object[] |  |\n| `data.items[].supply` | object | Rate-vs-amount sweep from size 0 to `fillable`. |\n| `data.items[].supply.side` | `borrow`, `supply` |  |\n| `data.items[].supply.currentUtilization` | number |  |\n| `data.items[].supply.currentBorrowAprPct` | number |  |\n| `data.items[].supply.currentDepositAprPct` | number |  |\n| `data.items[].supply.fillable` | number | Largest size sampled — the depth ceiling (token units). |\n| `data.items[].supply.fillableUsd` | number |  |\n| `data.items[].supply.points` | object[] |  |\n| `data.items[].rateAtAmount` | object[] | Rate + fillable at each requested size (present only when `amount(s)`/`amount(s)Usd` is passed). |\n| `data.items[].rateAtAmount[].side` | `borrow`, `supply` |  |\n| `data.items[].rateAtAmount[].size` | number | Requested size (token units) |\n| `data.items[].rateAtAmount[].amountUsd` | number |  |\n| `data.items[].rateAtAmount[].utilization` | number | Post-action utilization (0 for order books) |\n| `data.items[].rateAtAmount[].borrowAprPct` | number |  |\n| `data.items[].rateAtAmount[].depositAprPct` | number |  |\n| `data.items[].rateAtAmount[].fillable` | number | Max borrowable/suppliable before a cap binds (token units) |\n| `data.items[].rateAtAmount[].capped` | boolean | True when `size` exceeds `fillable` — rate is reported at the ceiling. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": [\n      {\n        \"marketUid\": \"AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"protocol\": \"string\",\n        \"lenderKey\": \"AAVE_V3\",\n        \"chainId\": \"1\",\n        \"underlyingAddress\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"utilization\": 1.0,\n        \"variableBorrowRate\": 1.0,\n        \"borrow\": {\n          \"side\": \"borrow\",\n          \"currentUtilization\": 1.0,\n          \"currentBorrowAprPct\": 1.0,\n          \"currentDepositAprPct\": 1.0,\n          \"fillable\": 1.0,\n          \"fillableUsd\": 1.0,\n          \"points\": [\n            {\n              \"size\": 1.0,\n              \"sizeUsd\": 1.0,\n              \"utilization\": 1.0,\n              \"borrowAprPct\": 1.0,\n              \"depositAprPct\": 1.0\n            }\n          ]\n        },\n        \"supply\": {\n          \"side\": \"borrow\",\n          \"currentUtilization\": 1.0,\n          \"currentBorrowAprPct\": 1.0,\n          \"currentDepositAprPct\": 1.0,\n          \"fillable\": 1.0,\n          \"fillableUsd\": 1.0,\n          \"points\": [\n            {\n              \"size\": 1.0,\n              \"sizeUsd\": 1.0,\n              \"utilization\": 1.0,\n              \"borrowAprPct\": 1.0,\n              \"depositAprPct\": 1.0\n            }\n          ]\n        },\n        \"rateAtAmount\": [\n          {\n            \"side\": \"borrow\",\n            \"size\": 1.0,\n            \"amountUsd\": 1.0,\n            \"utilization\": 1.0,\n            \"borrowAprPct\": 1.0,\n            \"depositAprPct\": 1.0,\n            \"fillable\": 1.0,\n            \"capped\": true\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated market UIDs, e.g. `GEARBOX_V3_0x…:9745:0x…`"
          },
          {
            "name": "side",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "borrow",
              "example": "borrow"
            },
            "description": "`borrow` | `supply` | `both` (default `borrow`)",
            "example": "borrow"
          },
          {
            "name": "dataPoints",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 24
            },
            "description": "Samples per grid (1–60, default 24)"
          },
          {
            "name": "amounts",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "12000"
            },
            "description": "Comma-separated sizes in TOKEN units → adds `rateAtAmount[]`. `amount` is accepted as a singular alias.",
            "example": "12000"
          },
          {
            "name": "amountsUsd",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated sizes in USD (converted per market via its price). `amountUsd` alias accepted."
          },
          {
            "name": "grid",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "true"
            },
            "description": "Set `false` to drop the 0→max grid sweep (points-only)."
          }
        ],
        "responses": {
          "200": {
            "description": "Depth grids and/or rate-at-amount points per market",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "count",
                        "items"
                      ],
                      "properties": {
                        "count": {
                          "type": "integer",
                          "description": "Number of entries in `items`."
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "marketUid",
                              "lenderKey",
                              "chainId"
                            ],
                            "properties": {
                              "marketUid": {
                                "type": "string",
                                "description": "Market identifier, formatted `lender:chainId:address`."
                              },
                              "protocol": {
                                "type": "string"
                              },
                              "lenderKey": {
                                "type": "string"
                              },
                              "chainId": {
                                "type": "string",
                                "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                              },
                              "underlyingAddress": {
                                "type": "string"
                              },
                              "utilization": {
                                "type": "number",
                                "nullable": true,
                                "description": "Current utilization (0–1)"
                              },
                              "variableBorrowRate": {
                                "type": "number",
                                "nullable": true,
                                "description": "Current 0-notional borrow APR %"
                              },
                              "borrow": {
                                "type": "object",
                                "description": "Rate-vs-amount sweep from size 0 to `fillable`.",
                                "properties": {
                                  "side": {
                                    "type": "string",
                                    "enum": [
                                      "borrow",
                                      "supply"
                                    ]
                                  },
                                  "currentUtilization": {
                                    "type": "number"
                                  },
                                  "currentBorrowAprPct": {
                                    "type": "number"
                                  },
                                  "currentDepositAprPct": {
                                    "type": "number"
                                  },
                                  "fillable": {
                                    "type": "number",
                                    "description": "Largest size sampled — the depth ceiling (token units)."
                                  },
                                  "fillableUsd": {
                                    "type": "number",
                                    "nullable": true
                                  },
                                  "points": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "size": {
                                          "type": "number",
                                          "description": "Cumulative size (token units)"
                                        },
                                        "sizeUsd": {
                                          "type": "number",
                                          "nullable": true
                                        },
                                        "utilization": {
                                          "type": "number",
                                          "description": "Market utilization, as a fraction between 0 and 1."
                                        },
                                        "borrowAprPct": {
                                          "type": "number"
                                        },
                                        "depositAprPct": {
                                          "type": "number"
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "supply": {
                                "type": "object",
                                "description": "Rate-vs-amount sweep from size 0 to `fillable`.",
                                "properties": {
                                  "side": {
                                    "type": "string",
                                    "enum": [
                                      "borrow",
                                      "supply"
                                    ]
                                  },
                                  "currentUtilization": {
                                    "type": "number"
                                  },
                                  "currentBorrowAprPct": {
                                    "type": "number"
                                  },
                                  "currentDepositAprPct": {
                                    "type": "number"
                                  },
                                  "fillable": {
                                    "type": "number",
                                    "description": "Largest size sampled — the depth ceiling (token units)."
                                  },
                                  "fillableUsd": {
                                    "type": "number",
                                    "nullable": true
                                  },
                                  "points": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "size": {
                                          "type": "number",
                                          "description": "Cumulative size (token units)"
                                        },
                                        "sizeUsd": {
                                          "type": "number",
                                          "nullable": true
                                        },
                                        "utilization": {
                                          "type": "number",
                                          "description": "Market utilization, as a fraction between 0 and 1."
                                        },
                                        "borrowAprPct": {
                                          "type": "number"
                                        },
                                        "depositAprPct": {
                                          "type": "number"
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "rateAtAmount": {
                                "type": "array",
                                "description": "Rate + fillable at each requested size (present only when `amount(s)`/`amount(s)Usd` is passed).",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "side",
                                    "size",
                                    "borrowAprPct",
                                    "depositAprPct",
                                    "fillable",
                                    "capped"
                                  ],
                                  "properties": {
                                    "side": {
                                      "type": "string",
                                      "enum": [
                                        "borrow",
                                        "supply"
                                      ]
                                    },
                                    "size": {
                                      "type": "number",
                                      "description": "Requested size (token units)"
                                    },
                                    "amountUsd": {
                                      "type": "number",
                                      "nullable": true
                                    },
                                    "utilization": {
                                      "type": "number",
                                      "description": "Post-action utilization (0 for order books)"
                                    },
                                    "borrowAprPct": {
                                      "type": "number"
                                    },
                                    "depositAprPct": {
                                      "type": "number"
                                    },
                                    "fillable": {
                                      "type": "number",
                                      "description": "Max borrowable/suppliable before a cap binds (token units)"
                                    },
                                    "capped": {
                                      "type": "boolean",
                                      "description": "True when `size` exceeds `fillable` — rate is reported at the ceiling."
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "description": "The result set for this response."
                        }
                      },
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "protocol": "string",
                        "lenderKey": "AAVE_V3",
                        "chainId": "1",
                        "underlyingAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "utilization": 1,
                        "variableBorrowRate": 1,
                        "borrow": {
                          "side": "borrow",
                          "currentUtilization": 1,
                          "currentBorrowAprPct": 1,
                          "currentDepositAprPct": 1,
                          "fillable": 1,
                          "fillableUsd": 1,
                          "points": [
                            {
                              "size": 1,
                              "sizeUsd": 1,
                              "utilization": 1,
                              "borrowAprPct": 1,
                              "depositAprPct": 1
                            }
                          ]
                        },
                        "supply": {
                          "side": "borrow",
                          "currentUtilization": 1,
                          "currentBorrowAprPct": 1,
                          "currentDepositAprPct": 1,
                          "fillable": 1,
                          "fillableUsd": 1,
                          "points": [
                            {
                              "size": 1,
                              "sizeUsd": 1,
                              "utilization": 1,
                              "borrowAprPct": 1,
                              "depositAprPct": 1
                            }
                          ]
                        },
                        "rateAtAmount": [
                          {
                            "side": "borrow",
                            "size": 1,
                            "amountUsd": 1,
                            "utilization": 1,
                            "borrowAprPct": 1,
                            "depositAprPct": 1,
                            "fillable": 1,
                            "capped": true
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "rate-at-depth-rate-vs-borrow-supply-amount"
      }
    },
    "/v1/data/lending/mode": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "List mode categories",
        "description": "Return the available risk-category (\"mode\") entries for the requested lenders and chains.\n\nEach entry contains the lender key, chain ID, and a list of mode categories (id + label) under the `eModes` field.\n\nThe \"mode\" terminology is the protocol-agnostic generalization of Aave V3's \"e-mode\" (efficiency mode); other lenders expose analogous category mechanisms.\n\nResults are cached server-side (1 hour TTL) because mode categories rarely change.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/mode`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `lenders` | query | string[] | yes | Protocol identifiers (repeatable) See the `LenderId` schema for the full set of accepted values. |\n| `chains` | query | string[] | yes | Chain IDs (repeatable) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "lenders",
            "in": "query",
            "required": true,
            "description": "Protocol identifiers (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3"
            ]
          },
          {
            "name": "chains",
            "in": "query",
            "required": true,
            "description": "Chain IDs (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Mode categories per lender/chain",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "list-mode-categories"
      }
    },
    "/v1/data/lending/mode/analysis": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Mode analysis (on-chain)",
        "description": "Evaluate all mode-switching options for a user. The API fetches the user's current positions and balance data on-chain via multicall — no request body needed.\n\n**Output:** For each available mode on the specified lender/chain, returns:\n- **healthFactor** — the hypothetical health factor if the user switches to that mode (`null` if no debt)\n- **supportedAssets** — which marketUids are eligible as collateral or for borrowing in that mode\n- **canSwitch** — whether the switch is safe (health factor > 1 and no incompatible debt)\n\nMode categories are cached server-side (1 hour TTL). Market configs are cached (3 minute TTL).\n\nThe \"mode\" terminology is the protocol-agnostic generalization of Aave V3's \"e-mode\" (efficiency mode); other lenders expose analogous category mechanisms.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/mode/analysis`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. |\n| `chain` | query | string | yes | Chain ID |\n| `operator` | query | string | yes | Wallet address of the user |\n| `accountId` | query | string | no | Sub-account ID (for multi-subaccount lenders like Init Capital). Defaults to first sub-account. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Protocol identifier See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID",
            "example": "1"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (for multi-subaccount lenders like Init Capital). Defaults to first sub-account."
          }
        ],
        "responses": {
          "200": {
            "description": "Mode analysis results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "mode-analysis-on-chain"
      },
      "post": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Mode analysis (with body)",
        "description": "Evaluate all mode-switching options for a user sub-account.\n\n**Input:** POST a `UserDataForSubAccount` object (the same shape returned by `/user-positions` per sub-account).\n\n**Output:** For each available mode on the specified lender/chain, returns:\n- **healthFactor** — the hypothetical health factor if the user switches to that mode (`null` if no debt)\n- **supportedAssets** — which marketUids are eligible as collateral or for borrowing in that mode\n- **canSwitch** — whether the switch is safe (health factor > 1 and no incompatible debt)\n\nMode categories are cached server-side (1 hour TTL). Market configs are cached (3 minute TTL).\n\nThe \"mode\" terminology is the protocol-agnostic generalization of Aave V3's \"e-mode\" (efficiency mode); other lenders expose analogous category mechanisms.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/lending/mode/analysis`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. |\n| `chain` | query | string | yes | Chain ID |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `accountId` | string | no |  |\n| `health` | number | no |  |\n| `borrowCapacityUSD` | number | no |  |\n| `balanceData` | object | yes | Balance data for the sub-account. `collateral` and `adjustedDebt` are required for health factor calculation. |\n| `balanceData.collateral` | number | yes |  |\n| `balanceData.adjustedDebt` | number | yes |  |\n| `balanceData.deposits` | number | no |  |\n| `balanceData.debt` | number | no |  |\n| `balanceData.borrowDiscountedCollateral` | number | no |  |\n| `balanceData.nav` | number | no |  |\n| `aprData` | object | no |  |\n| `positions` | object[] | yes |  |\n| `positions[].marketUid` | string | no | Market identifier, formatted `lender:chainId:address`. |\n| `positions[].depositsUSD` | number | no |  |\n| `positions[].debtUSD` | number | no |  |\n| `positions[].debtStableUSD` | number | no |  |\n| `positions[].collateralEnabled` | boolean | no |  |\n| `userConfig` | object | yes |  |\n| `userConfig.selectedMode` | string | yes | Current mode/config key |\n| `userConfig.id` | string | no |  |\n| `userConfig.isWhitelisted` | boolean | no |  |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Protocol identifier See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID",
            "example": "1"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "A `UserDataForSubAccount` object. Validation returns specific field-level errors (e.g. \"missing field: balanceData.collateral (number)\").",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "balanceData",
                  "positions",
                  "userConfig"
                ],
                "properties": {
                  "accountId": {
                    "type": "string"
                  },
                  "health": {
                    "type": "number",
                    "nullable": true
                  },
                  "borrowCapacityUSD": {
                    "type": "number"
                  },
                  "balanceData": {
                    "type": "object",
                    "required": [
                      "collateral",
                      "adjustedDebt"
                    ],
                    "description": "Balance data for the sub-account. `collateral` and `adjustedDebt` are required for health factor calculation.",
                    "properties": {
                      "collateral": {
                        "type": "number"
                      },
                      "adjustedDebt": {
                        "type": "number"
                      },
                      "deposits": {
                        "type": "number"
                      },
                      "debt": {
                        "type": "number"
                      },
                      "borrowDiscountedCollateral": {
                        "type": "number"
                      },
                      "nav": {
                        "type": "number"
                      }
                    }
                  },
                  "aprData": {
                    "type": "object"
                  },
                  "positions": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "marketUid": {
                          "type": "string",
                          "description": "Market identifier, formatted `lender:chainId:address`."
                        },
                        "depositsUSD": {
                          "type": "number"
                        },
                        "debtUSD": {
                          "type": "number"
                        },
                        "debtStableUSD": {
                          "type": "number"
                        },
                        "collateralEnabled": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "userConfig": {
                    "type": "object",
                    "required": [
                      "selectedMode"
                    ],
                    "properties": {
                      "selectedMode": {
                        "type": "string",
                        "description": "Current mode/config key"
                      },
                      "id": {
                        "type": "string"
                      },
                      "isWhitelisted": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              },
              "example": {
                "accountId": "string",
                "health": 1,
                "borrowCapacityUSD": 1,
                "balanceData": {
                  "collateral": 1,
                  "adjustedDebt": 1,
                  "deposits": 1,
                  "debt": 1,
                  "borrowDiscountedCollateral": 1,
                  "nav": 1
                },
                "aprData": {},
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                    "depositsUSD": 1,
                    "debtUSD": 1,
                    "debtStableUSD": 1,
                    "collateralEnabled": true
                  }
                ],
                "userConfig": {
                  "selectedMode": "string",
                  "id": "string",
                  "isWhitelisted": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mode analysis results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "mode-analysis-with-body"
      }
    },
    "/v1/data/lending/next-account": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Next available sub-account",
        "description": "Discover the next available sub-account or position ID for a given lender and owner.\n\nDifferent protocols handle sub-accounts differently:\n\n- **Euler V2** (`accountType: SELECT`): Sub-accounts are derived by XORing the owner's last address byte with an index (0-255). The integrator selects an `accountId` from the range. Any unused value automatically creates a new sub-account.\n- **Dolomite** (`accountType: SELECT`): Margin sub-accounts are arbitrary `uint256` account numbers (`accountIdRange` is `0` to `2^256-1`). Account `0` is the default cross-margin account; `activeAccountIds` lists funded accounts and `nextAccountId` is the lowest unused integer. Any unused number automatically creates a new sub-account.\n- **Init Capital** (`accountType: AUTOGEN`): Position IDs are NFT hashes generated on-chain. To create a new position, **omit** the `posId`/`accountId` parameter entirely. The `nextAccountId` field is a preview of the ID that will be generated.\n- **Other lenders** (Aave, Morpho, Compound, etc.): Do not support sub-accounts — returns a 400 error.\n\n### Integration Guide\n\n| `accountType` | To create new account | To use existing account |\n|---|---|---|\n| `SELECT` | Pass `accountId=<unused value>` from `accountIdRange` | Pass `accountId=<existing value>` |\n| `AUTOGEN` | **Omit** `accountId` / `posId` parameter | Pass `posId=<existing ID>` |\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/next-account`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID. See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Lender identifier. See the `LenderId` schema for the full set of accepted values. |\n| `account` | query | string | yes | Owner wallet address. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.accountType` | `SELECT`, `AUTOGEN` | SELECT — integrator picks an ID from the range (Euler V2). AUTOGEN — ID is generated on-chain; omit the param to create (Init Capital). |\n| `data.nextAccountId` | string | For SELECT: lowest unused account ID. For AUTOGEN: preview of the on-chain generated ID. |\n| `data.activeAccountIds` | string[] | Currently active account IDs for this owner. May be empty for AUTOGEN protocols. |\n| `data.accountIdRange` | string[] | Inclusive [min, max] range of valid account IDs. |\n| `data.createHint` | string | Human-readable instructions for integrators on how to create a new sub-account. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"accountType\": \"SELECT\",\n    \"nextAccountId\": \"1\",\n    \"activeAccountIds\": [\n      \"0\",\n      \"3\",\n      \"7\"\n    ],\n    \"accountIdRange\": [\n      \"0\",\n      \"255\"\n    ],\n    \"createHint\": \"string\"\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID. See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "EULER_V2"
            },
            "description": "Lender identifier. See the `LenderId` schema for the full set of accepted values.",
            "example": "EULER_V2"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Owner wallet address.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          }
        ],
        "responses": {
          "200": {
            "description": "Next account information",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/NextAccountResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "accountType": "SELECT",
                    "nextAccountId": "1",
                    "activeAccountIds": [
                      "0",
                      "3",
                      "7"
                    ],
                    "accountIdRange": [
                      "0",
                      "255"
                    ],
                    "createHint": "string"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "next-available-sub-account"
      }
    },
    "/v1/data/lending/orders": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Your open orders (unified)",
        "operationId": "lending-orders",
        "description": "A user's own cancellable/pending orders on an order-book or auction lender, normalized into ONE shape:\n- `MORPHO_MIDNIGHT_<id>` → signed maker limit offers (`kind: 'maker-offer'`), cancel via [`/v1/actions/midnight/cancel`](/1delta-api/midnight-cancel).\n- `TERM_FINANCE_<id>` → secondary repo-token listings (`kind: 'listing'`) + primary sealed-bid auction submissions (`kind: 'auction-offer'|'auction-bid'`), managed via [`/v1/actions/term/*`](/1delta-api/term-offer).\n\nEach order carries a self-describing `cancel` action (`{ method, path, query }`) pointing at the exact endpoint, so one Cancel button works for every provider. `aprPct` is `null` while an auction price is still sealed. To TAKE (fill) *other* users' liquidity, use the standard lending actions + the unified ladder at `/v1/data/lending/book`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/orders`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | no | Market uid `lender:chainId:asset` (or pass `lender` + `chainId`). |\n| `lender` | query | string | no | `MORPHO_MIDNIGHT_<id>` or `TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values. |\n| `chainId` | query | string | no | Chain ID (aliases: `chains`, `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | The order owner whose orders to return. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | A user's own orders across order-book / auction lenders. |\n| `data.orders` | object[] |  |\n| `data.orders[].id` | string | Provider order id — the cancel target (Midnight offer root / Term listingId / auction submission id). |\n| `data.orders[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.orders[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.orders[].kind` | `maker-offer`, `listing`, `auction-offer`, `auction-bid` | `maker-offer` (Midnight signed limit offer), `listing` (Term secondary repo-token listing), `auction-offer`/`auction-bid` (Term primary sealed-bid submission). |\n| `data.orders[].side` | `lend`, `borrow` |  |\n| `data.orders[].amount` | string | Order size, loan-token base units. |\n| `data.orders[].assets` | number | Size decimal-scaled to loan-token assets, or null. |\n| `data.orders[].aprPct` | number | Annualized rate in percent, or null while sealed. |\n| `data.orders[].status` | `open`, `sealed`, `revealed`, `filled`, `closed` | `open` = cancellable now (maker offer / listing); `sealed`/`revealed` = auction lifecycle; `filled` = assigned at clearing; `closed` = complete or cancelled. |\n| `data.orders[].filledAmount` | string | Amount assigned at clearing (auctions), base units. |\n| `data.orders[].maturity` | number | Market/repo maturity, unix seconds. |\n| `data.orders[].expiry` | number | Maker-offer expiry, unix seconds (Midnight). |\n| `data.orders[].revealTime` | number | Auction reveal window opens, unix seconds (Term). |\n| `data.orders[].auctionEndTime` | number | Auction closes / clears, unix seconds (Term). |\n| `data.orders[].cancel` | object | Self-describing cancel/unlock action — omitted when not cancellable. Fetch `path`+`query` to build the cancel transaction. |\n| `data.orders[].cancel.method` | `GET`, `POST` |  |\n| `data.orders[].cancel.path` | string |  |\n| `data.orders[].cancel.query` | object |  |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"orders\": [\n      {\n        \"id\": \"string\",\n        \"lender\": \"TERM_FINANCE_0xABC\\u2026\",\n        \"chainId\": \"1\",\n        \"kind\": \"maker-offer\",\n        \"side\": \"lend\",\n        \"amount\": \"1000000000000000000\",\n        \"assets\": 1.0,\n        \"aprPct\": 1.0,\n        \"status\": \"open\",\n        \"filledAmount\": \"1000000000000000000\",\n        \"maturity\": 1.0,\n        \"expiry\": 1.0,\n        \"revealTime\": 1.0,\n        \"auctionEndTime\": 1.0,\n        \"cancel\": {\n          \"method\": \"GET\",\n          \"path\": \"/v1/actions/term/unlock-offers\",\n          \"query\": {}\n        }\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…:1:0xA0b8…"
            },
            "description": "Market uid `lender:chainId:asset` (or pass `lender` + `chainId`).",
            "example": "TERM_FINANCE_0xABC…:1:0xA0b8…"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…"
            },
            "description": "`MORPHO_MIDNIGHT_<id>` or `TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values.",
            "example": "TERM_FINANCE_0xABC…"
          },
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID (aliases: `chains`, `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The order owner whose orders to return."
          }
        ],
        "responses": {
          "200": {
            "description": "The account's own orders on the market",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/UnifiedOrdersResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "orders": [
                      {
                        "id": "string",
                        "lender": "TERM_FINANCE_0xABC…",
                        "chainId": "1",
                        "kind": "maker-offer",
                        "side": "lend",
                        "amount": "1000000000000000000",
                        "assets": 1,
                        "aprPct": 1,
                        "status": "open",
                        "filledAmount": "1000000000000000000",
                        "maturity": 1,
                        "expiry": 1,
                        "revealTime": 1,
                        "auctionEndTime": 1,
                        "cancel": {
                          "method": "GET",
                          "path": "/v1/actions/term/unlock-offers",
                          "query": {}
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/loop/range/leverage": {
      "get": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max leverage range",
        "description": "Compute the maximum amount that can be opened in a leverage position.\n\n**Single-pair mode** (provide `marketUidIn` + `marketUidOut`): returns the max open amount for one specific pair.\n\n**Multi-pair mode** (provide `lender` + `chainId`): returns the max open amount for all leverage pairs of a lender, optionally filtered by `marketUidIn` / `marketUidOut`.\n\n**Zap mode**: If `payAmount` and `payPriceUSD` are provided, the calculation includes the deposited amount as additional collateral before computing the leverage range.\n\nGET fetches user balances on-chain (requires `account`). POST accepts a `SimulationBody` in the request body.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/loop/range/leverage`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `lender` | query | string | no | Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values. |\n| `chainId` | query | string | no | Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains. |\n| `payAmount` | query | string | no | Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present. |\n| `payPriceUSD` | query | string | no | USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "payAmount",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present."
          },
          {
            "name": "payPriceUSD",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair."
          }
        ],
        "responses": {
          "200": {
            "description": "Max open range for one or more leverage pairs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/RangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-leverage-range"
      },
      "post": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max leverage range (with body)",
        "description": "Compute the maximum amount that can be opened in a leverage position.\n\n**Single-pair mode** (provide `marketUidIn` + `marketUidOut`): returns the max open amount for one specific pair.\n\n**Multi-pair mode** (provide `lender` + `chainId`): returns the max open amount for all leverage pairs of a lender, optionally filtered by `marketUidIn` / `marketUidOut`.\n\n**Zap mode**: If `payAmount` and `payPriceUSD` are provided, the calculation includes the deposited amount as additional collateral before computing the leverage range.\n\nGET fetches user balances on-chain (requires `account`). POST accepts a `SimulationBody` in the request body.\n\nPOST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/loop/range/leverage`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `lender` | query | string | no | Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values. |\n| `chainId` | query | string | no | Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains. |\n| `payAmount` | query | string | no | Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present. |\n| `payPriceUSD` | query | string | no | USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "payAmount",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present."
          },
          {
            "name": "payPriceUSD",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Max open range for one or more leverage pairs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/RangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-leverage-range-with-body"
      }
    },
    "/v1/data/loop/range/collateral-swap": {
      "get": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max collateral swap range",
        "description": "Compute the maximum amount for a collateral swap.\n\nThe max swappable amount equals the user's collateral deposit in the source (input) asset.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read the user's collateral balances.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/loop/range/collateral-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          }
        ],
        "responses": {
          "200": {
            "description": "Max collateral swap range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/CollateralSwapRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-collateral-swap-range"
      },
      "post": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max collateral swap range (with body)",
        "description": "Compute the maximum amount for a collateral swap.\n\nThe max swappable amount equals the user's collateral deposit in the source (input) asset.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read the user's collateral balances.\n\nPOST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/loop/range/collateral-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Max collateral swap range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/CollateralSwapRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-collateral-swap-range-with-body"
      }
    },
    "/v1/data/loop/range/debt-swap": {
      "get": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max debt swap range",
        "description": "Compute the maximum amount for a debt swap.\n\nThe max swappable amount equals the user's total debt (variable + stable) in the source (input) asset.\n\nUse `denomination=exactInput` (default) to base the range on the source debt, or `exactOutput` to base it on the target debt.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read the user's debt balances.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/loop/range/debt-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `denomination` | query | `exactInput`, `exactOutput` | no | Which side is the base denomination for the range. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "denomination",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "exactInput",
                "exactOutput"
              ],
              "default": "exactInput"
            },
            "description": "Which side is the base denomination for the range."
          }
        ],
        "responses": {
          "200": {
            "description": "Max debt swap range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/DebtSwapRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-debt-swap-range"
      },
      "post": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max debt swap range (with body)",
        "description": "Compute the maximum amount for a debt swap.\n\nThe max swappable amount equals the user's total debt (variable + stable) in the source (input) asset.\n\nUse `denomination=exactInput` (default) to base the range on the source debt, or `exactOutput` to base it on the target debt.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read the user's debt balances.\n\nPOST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/loop/range/debt-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `denomination` | query | `exactInput`, `exactOutput` | no | Which side is the base denomination for the range. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "denomination",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "exactInput",
                "exactOutput"
              ],
              "default": "exactInput"
            },
            "description": "Which side is the base denomination for the range."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Max debt swap range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/DebtSwapRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-debt-swap-range-with-body"
      }
    },
    "/v1/data/loop/range/close": {
      "get": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max close range",
        "description": "Compute the maximum amount for closing (deleveraging) a position.\n\nThe max closeable amount is bounded by the smaller of the user's collateral and debt. `amountIn` = collateral withdrawn, `amountOut` = debt repaid.\n\nUse `denomination=exactInput` (default) to base the range on collateral, or `exactOutput` to base it on debt.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read collateral and debt balances.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/loop/range/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `denomination` | query | `exactInput`, `exactOutput` | no | Which side is the base denomination for the range. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "denomination",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "exactInput",
                "exactOutput"
              ],
              "default": "exactInput"
            },
            "description": "Which side is the base denomination for the range."
          }
        ],
        "responses": {
          "200": {
            "description": "Max close range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/CloseRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-close-range"
      },
      "post": {
        "tags": [
          "Loop (Data)"
        ],
        "summary": "Max close range (with body)",
        "description": "Compute the maximum amount for closing (deleveraging) a position.\n\nThe max closeable amount is bounded by the smaller of the user's collateral and debt. `amountIn` = collateral withdrawn, `amountOut` = debt repaid.\n\nUse `denomination=exactInput` (default) to base the range on collateral, or `exactOutput` to base it on debt.\n\nRequires `positions[]` in the POST body (or `account` for GET) to read collateral and debt balances.\n\nPOST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/loop/range/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. |\n| `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. |\n| `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). |\n| `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). |\n| `denomination` | query | `exactInput`, `exactOutput` | no | Which side is the base denomination for the range. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object[] | Array of range results. |\n| `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data[].lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data[].marketLongUid` | string | Market UID of the collateral side |\n| `data[].marketShortUid` | string | Market UID of the debt side |\n| `data[].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. |\n| `data[].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. |\n| `data[].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. |\n| `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. |\n| `data[].assetLong` | string | Collateral asset address |\n| `data[].assetShort` | string | Debt asset address |\n| `data[].assetGroupLong` | string |  |\n| `data[].assetGroupShort` | string |  |\n| `data[].symbolLong` | string | Collateral token symbol |\n| `data[].nameLong` | string | Collateral token name |\n| `data[].symbolShort` | string | Debt token symbol |\n| `data[].nameShort` | string | Debt token name |\n| `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side |\n| `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side |\n| `data[].borrowFactorLong` | number | Borrow factor for the long side |\n| `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset |\n| `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset |\n| `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side |\n| `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side |\n| `data[].borrowFactorShort` | number | Borrow factor for the short side |\n| `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset |\n| `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset |\n| `data[].eModeConfigId` | string | E-mode configuration ID |\n| `data[].eMode` | string | E-mode category |\n| `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) |\n| `data[].aprTotal` | number | Total APR (base + rewards) |\n| `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. |\n| `data[].ltv` | number | Loan-to-value ratio (0-1) |\n| `data[].depositRateLong` | number |  |\n| `data[].variableBorrowRateShort` | number |  |\n| `data[].intrinsicYieldLong` | number |  |\n| `data[].intrinsicYieldShort` | number |  |\n| `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. |\n| `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"chainId\": \"1\",\n      \"lender\": \"AAVE_V3\",\n      \"marketLongUid\": \"string\",\n      \"marketShortUid\": \"string\",\n      \"marketNameLong\": \"string\",\n      \"marketNameShort\": \"string\",\n      \"curatorNameLong\": \"string\",\n      \"curatorNameShort\": \"string\",\n      \"assetLong\": \"string\",\n      \"assetShort\": \"string\",\n      \"assetGroupLong\": \"string\",\n      \"assetGroupShort\": \"string\",\n      \"symbolLong\": \"string\",\n      \"nameLong\": \"string\",\n      \"symbolShort\": \"string\",\n      \"nameShort\": \"string\",\n      \"collateralFactorLong\": 0.94,\n      \"borrowCollateralFactorLong\": 0.92,\n      \"borrowFactorLong\": 1,\n      \"collateralDisabledLong\": true,\n      \"debtDisabledLong\": true,\n      \"collateralFactorShort\": 0.94,\n      \"borrowCollateralFactorShort\": 0.92,\n      \"borrowFactorShort\": 1,\n      \"collateralDisabledShort\": true,\n      \"debtDisabledShort\": true,\n      \"eModeConfigId\": \"string\",\n      \"eMode\": \"string\",\n      \"aprBase\": 1.0,\n      \"aprTotal\": 1.0,\n      \"maxLeverage\": 1.0,\n      \"ltv\": 1.0,\n      \"depositRateLong\": 1.0,\n      \"variableBorrowRateShort\": 1.0,\n      \"intrinsicYieldLong\": 1.0,\n      \"intrinsicYieldShort\": 1.0,\n      \"variableBorrowDisabledShort\": true,\n      \"termsShort\": [\n        {\n          \"termId\": 2,\n          \"depositApr\": 1.0,\n          \"available\": 1.0,\n          \"durationDays\": 7,\n          \"durationSecs\": 604800,\n          \"apr\": 3.85,\n          \"aprAtAmount\": 1.0,\n          \"fillable\": 1.0,\n          \"capped\": true,\n          \"ladder\": [\n            {\n              \"apr\": 1.0,\n              \"units\": \"string\",\n              \"assets\": 1.0\n            }\n          ]\n        }\n      ],\n      \"fixedTerm\": {\n        \"model\": \"term\",\n        \"maturity\": 1,\n        \"fees\": {},\n        \"earlyRepay\": {},\n        \"provider\": {},\n        \"auction\": {\n          \"status\": \"open\",\n          \"canBorrow\": true,\n          \"canLend\": true,\n          \"secondsUntilClose\": 263000,\n          \"implications\": [\n            \"string\"\n          ],\n          \"id\": \"string\",\n          \"startTime\": 1,\n          \"revealTime\": 1,\n          \"endTime\": 1,\n          \"minBorrowAmount\": \"1000000000\",\n          \"minLendAmount\": \"1000000000\"\n        }\n      },\n      \"rewardAprLong\": 1.0,\n      \"rewardAprShort\": 1.0,\n      \"rewardsLong\": [\n        {}\n      ],\n      \"rewardsShort\": [\n        {}\n      ],\n      \"totalDepositsLong\": 1.0,\n      \"totalDebtLong\": 1.0,\n      \"totalLiquidityLong\": 1.0,\n      \"totalDepositsShort\": 1.0,\n      \"totalDebtShort\": 1.0,\n      \"totalLiquidityShort\": 1.0,\n      \"totalDepositsUsdLong\": 1.0,\n      \"totalDebtUsdLong\": 1.0,\n      \"totalLiquidityUsdLong\": 1.0,\n      \"totalDepositsUsdShort\": 1.0,\n      \"totalDebtUsdShort\": 1.0,\n      \"totalLiquidityUsdShort\": 1.0,\n      \"borrowLiquidityShort\": 1.0,\n      \"withdrawLiquidityLong\": 1.0,\n      \"depositableLong\": 1.0,\n      \"utilizationLong\": 1.0,\n      \"utilizationShort\": 1.0,\n      \"underlyingInfoLong\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      },\n      \"underlyingInfoShort\": {\n        \"asset\": {},\n        \"prices\": {},\n        \"oraclePrice\": {}\n      }\n    }\n  ]\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for the input (debt/short) side.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for the output (collateral/long) side.",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address. Required for GET (on-chain balance fetch).",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Sub-account ID (e.g. Euler V2, Init Capital)."
          },
          {
            "name": "denomination",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "exactInput",
                "exactOutput"
              ],
              "default": "exactInput"
            },
            "description": "Which side is the base denomination for the range."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Max close range",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "array",
                      "description": "Array of range results.",
                      "items": {
                        "$ref": "#/components/schemas/CloseRangeResult"
                      }
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "chainId": "1",
                      "lender": "AAVE_V3",
                      "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",
                      "collateralFactorLong": 0.94,
                      "borrowCollateralFactorLong": 0.92,
                      "borrowFactorLong": 1,
                      "collateralDisabledLong": true,
                      "debtDisabledLong": true,
                      "collateralFactorShort": 0.94,
                      "borrowCollateralFactorShort": 0.92,
                      "borrowFactorShort": 1,
                      "collateralDisabledShort": true,
                      "debtDisabledShort": true,
                      "eModeConfigId": "string",
                      "eMode": "string",
                      "aprBase": 1,
                      "aprTotal": 1,
                      "maxLeverage": 1,
                      "ltv": 1,
                      "depositRateLong": 1,
                      "variableBorrowRateShort": 1,
                      "intrinsicYieldLong": 1,
                      "intrinsicYieldShort": 1,
                      "variableBorrowDisabledShort": true,
                      "termsShort": [
                        {
                          "termId": 2,
                          "depositApr": 1,
                          "available": 1,
                          "durationDays": 7,
                          "durationSecs": 604800,
                          "apr": 3.85,
                          "aprAtAmount": 1,
                          "fillable": 1,
                          "capped": true,
                          "ladder": [
                            {
                              "apr": 1,
                              "units": "string",
                              "assets": 1
                            }
                          ]
                        }
                      ],
                      "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"
                        }
                      },
                      "rewardAprLong": 1,
                      "rewardAprShort": 1,
                      "rewardsLong": [
                        {}
                      ],
                      "rewardsShort": [
                        {}
                      ],
                      "totalDepositsLong": 1,
                      "totalDebtLong": 1,
                      "totalLiquidityLong": 1,
                      "totalDepositsShort": 1,
                      "totalDebtShort": 1,
                      "totalLiquidityShort": 1,
                      "totalDepositsUsdLong": 1,
                      "totalDebtUsdLong": 1,
                      "totalLiquidityUsdLong": 1,
                      "totalDepositsUsdShort": 1,
                      "totalDebtUsdShort": 1,
                      "totalLiquidityUsdShort": 1,
                      "borrowLiquidityShort": 1,
                      "withdrawLiquidityLong": 1,
                      "depositableLong": 1,
                      "utilizationLong": 1,
                      "utilizationShort": 1,
                      "underlyingInfoLong": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      },
                      "underlyingInfoShort": {
                        "asset": {},
                        "prices": {},
                        "oraclePrice": {}
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "max-close-range-with-body"
      }
    },
    "/v1/data/lending/yields/intrinsic/latest": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get latest intrinsic yields",
        "description": "Returns latest intrinsic yield (APR) for each asset group.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/intrinsic/latest`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `assets` | query | string[] | no | Filter by asset group keys (repeatable) |\n| `asOf` | query | string | no | ISO date anchor; defaults to latest hour |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.asOf` | string | Timestamp the data was measured at. |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.intrinsicApr` | object | Map of asset_group → APR in percent |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"asOf\": \"2026-01-01T00:00:00Z\",\n    \"count\": 1,\n    \"intrinsicApr\": {\n      \"USDC\": 3.25,\n      \"ETH\": 2.1\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "assets",
            "in": "query",
            "description": "Filter by asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          },
          {
            "name": "asOf",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-01-15T12:00:00Z"
            },
            "description": "ISO date anchor; defaults to latest hour",
            "example": "2025-01-15T12:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Intrinsic yield data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/IntrinsicYieldResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "asOf": "2026-01-01T00:00:00Z",
                    "count": 1,
                    "intrinsicApr": {
                      "USDC": 3.25,
                      "ETH": 2.1
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-latest-intrinsic-yields"
      }
    },
    "/v1/data/lending/yields/intrinsic/snapshots": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get intrinsic yield snapshots",
        "description": "Returns historical intrinsic yield time series per asset group.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/intrinsic/snapshots`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `assetGroups` | query | string[] | yes | Asset group keys (repeatable) |\n| `start` | query | string | no | ISO start date |\n| `end` | query | string | no | ISO end date |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.series` | object | Map of assetGroup → array of {dataTs, intrinsicYield} |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"series\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "assetGroups",
            "in": "query",
            "required": true,
            "description": "Asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-01T00:00:00Z"
            },
            "description": "ISO start date",
            "example": "2025-11-01T00:00:00Z"
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-15T00:00:00Z"
            },
            "description": "ISO end date",
            "example": "2025-11-15T00:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Intrinsic yield snapshots",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/IntrinsicYieldSnapshotResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "series": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-intrinsic-yield-snapshots"
      }
    },
    "/v1/data/lending/yields/by-asset/latest": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get latest yields by asset",
        "description": "Returns latest lending yields grouped by asset for a given chain.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/by-asset/latest`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `assets` | query | string[] | no | Filter by asset group keys (repeatable) |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"data\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "assets",
            "in": "query",
            "description": "Filter by asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Yield data by asset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LenderYieldResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-latest-yields-by-asset"
      }
    },
    "/v1/data/lending/yields/by-asset/snapshots": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get yield snapshots by asset",
        "description": "Returns historical yield time series grouped by asset for a given chain.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/by-asset/snapshots`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `assets` | query | string[] | no | Filter by asset group keys (repeatable) |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. |\n| `start` | query | string | no | ISO start date |\n| `end` | query | string | no | ISO end date |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"data\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "assets",
            "in": "query",
            "description": "Filter by asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-01T00:00:00Z"
            },
            "description": "ISO start date",
            "example": "2025-11-01T00:00:00Z"
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-15T00:00:00Z"
            },
            "description": "ISO end date",
            "example": "2025-11-15T00:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Yield snapshot data by asset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LenderYieldResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-yield-snapshots-by-asset"
      }
    },
    "/v1/data/lending/yields/by-lender/latest": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get latest yields by lender",
        "description": "Returns latest lending yields grouped by protocol.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/by-lender/latest`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"data\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainIds",
            "in": "query",
            "description": "Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "42161"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "42161"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Yield data by lender",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LenderYieldResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-latest-yields-by-lender"
      }
    },
    "/v1/data/lending/yields/by-lender/snapshots": {
      "get": {
        "tags": [
          "Yields"
        ],
        "summary": "Get yield snapshots by lender",
        "description": "Returns historical yield time series grouped by protocol.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/yields/by-lender/snapshots`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. |\n| `start` | query | string | no | ISO start date |\n| `end` | query | string | no | ISO end date |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"data\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainIds",
            "in": "query",
            "description": "Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "42161"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "42161"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-01T00:00:00Z"
            },
            "description": "ISO start date",
            "example": "2025-11-01T00:00:00Z"
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-15T00:00:00Z"
            },
            "description": "ISO end date",
            "example": "2025-11-15T00:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Yield snapshot data by lender",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LenderYieldResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-yield-snapshots-by-lender"
      }
    },
    "/v1/data/lending/user-positions": {
      "get": {
        "tags": [
          "User Positions"
        ],
        "summary": "User positions",
        "description": "Fetches lending and borrowing positions for a given account across one or more chains.\n\n**Response Structure:**\n- `items`: Flat array of lender entries sorted by net worth (descending). Each entry fuses sub-account position data with aggregated summary metrics (deposits, debt, APRs, health, leverage).\n- `summary`: Portfolio-wide totals (net worth, APRs, leverage, active counts) plus per-chain breakdowns.\n- `partial` / `incompleteLenders`: only present when some lender could not be read in full (RPC error or reverted call). A lender whose reads all failed is omitted rather than returned as an empty position, so totals are a lower bound for that request.\n\n**Lender Entry includes:**\n- Per-asset deposits and debt (in USD and token units)\n- Sub-account data with health factors and borrow capacity\n- Aggregated lender-level metrics (total deposits/debt, weighted APRs, health factor, leverage)\n- Collateral status, withdrawable/borrowable amounts per position\n\n**Portfolio Summary includes:**\n- Total deposits, debt, and net worth (current + 24h ago) across all chains\n- Weighted average APRs and overall leverage ratio\n- Count of active lenders and chains\n- Per-chain totals (deposits, debt, net worth, lender count)\n\nThe server executes RPC calls internally and returns fully parsed results.\n\n---\n\n**Using with action endpoints (POST simulation):**\n\nAll action endpoints (`/v1/actions/lending/*`, `/v1/actions/loop/*`) accept an optional POST body for post-trade simulation. The data comes directly from this endpoint:\n\n```\n// 1. Fetch positions\nGET /v1/data/lending/user-positions?account=0x...&chains=1\n\n// 2. Pick the lender entry + sub-account you're acting on\nconst sub = response.data.items[i].data[j]\n\n// 3. POST to any action endpoint with the same query params as GET, plus:\nPOST /v1/actions/lending/deposit?marketUid=AAVE_V3:1:0x...&amount=1000000\n{\n  \"balanceData\": sub.balanceData,\n  \"aprData\": sub.aprData,\n  \"positions\": sub.positions,\n  \"modeId\": sub.userConfig.selectedMode\n}\n\n// 4. Response includes a \"simulation\" field with pre/post health factor,\n//    borrow capacity, and projected balanceData/aprData.\n```\n\nSee the `SimulationBody` schema for full details.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/user-positions`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) |\n| `chains` | query | string | yes | Comma-separated chain IDs |\n| `lenders` | query | string | no | Comma-separated lender IDs to filter by. If omitted, all supported lenders for each chain are included. See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | User lending positions as a flat array with portfolio summary and per-chain breakdowns. |\n| `data.items` | object[] | Flat array of lender entries sorted by net worth (descending). Each entry fuses position data with aggregated summary metrics. |\n| `data.items[].lender` | string | Lender identifier |\n| `data.items[].chainId` | string | Chain ID |\n| `data.items[].account` | string | User account address |\n| `data.items[].data` | object[] | Sub-account position data |\n| `data.items[].data[].accountId` | string | Sub-account identifier (e.g., \"0\" for default, NFT ID for Init) |\n| `data.items[].data[].health` | number | Health factor (null if no debt). Values > 1 are healthy, < 1 at risk of liquidation. |\n| `data.items[].data[].borrowCapacityUSD` | number | Total USD borrowable while maintaining health >= 1 |\n| `data.items[].data[].balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.items[].data[].aprData` | object | APR breakdown for a sub-account. |\n| `data.items[].data[].positions` | object[] | Individual asset positions in this sub-account |\n| `data.items[].data[].userConfig` | object | User configuration for a sub-account. |\n| `data.items[].balanceData` | object | Summary-level balance data (without discounted/adjusted fields). |\n| `data.items[].balanceData.deposits` | number | Total deposits in USD |\n| `data.items[].balanceData.debt` | number | Total debt in USD |\n| `data.items[].balanceData.collateral` | number | Collateral value in USD |\n| `data.items[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled |\n| `data.items[].balanceData.nav` | number | Net asset value (deposits - debt) |\n| `data.items[].balanceData.deposits24h` | number | Deposits 24h ago |\n| `data.items[].balanceData.debt24h` | number | Debt 24h ago |\n| `data.items[].balanceData.nav24h` | number | NAV 24h ago |\n| `data.items[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. |\n| `data.items[].aprData` | object | Summary-level APR breakdown. |\n| `data.items[].aprData.apr` | number | Net APR (deposit - borrow) |\n| `data.items[].aprData.depositApr` | number | Weighted deposit APR |\n| `data.items[].aprData.borrowApr` | number | Weighted borrow APR |\n| `data.items[].aprData.rewardApr` | number | Total reward APR |\n| `data.items[].aprData.rewardDepositApr` | number | Reward APR on deposits |\n| `data.items[].aprData.rewardBorrowApr` | number | Reward APR on borrows |\n| `data.items[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) |\n| `data.items[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits |\n| `data.items[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows |\n| `data.items[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `data.items[].leverage` | number | Leverage ratio (deposits / nav) |\n| `data.summary` | object | Portfolio-wide totals with per-chain breakdowns. Per-lender summaries are fused into each LenderDataEntry in the items array. |\n| `data.summary.balanceData` | object | Summary-level balance data (without discounted/adjusted fields). |\n| `data.summary.balanceData.deposits` | number | Total deposits in USD |\n| `data.summary.balanceData.debt` | number | Total debt in USD |\n\n</details>\n",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
            },
            "description": "EVM account address (0x-prefixed, 40 hex chars)",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          {
            "name": "chains",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1,42161"
            },
            "description": "Comma-separated chain IDs",
            "example": "1,42161"
          },
          {
            "name": "lenders",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3,COMPOUND_V3_WETH"
            },
            "description": "Comma-separated lender IDs to filter by. If omitted, all supported lenders for each chain are included. See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3,COMPOUND_V3_WETH"
          }
        ],
        "responses": {
          "200": {
            "description": "User position data with portfolio summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/UserPositionResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "lender": "AAVE_V3",
                        "chainId": "1",
                        "account": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5",
                        "data": [
                          {
                            "accountId": "0",
                            "health": 1.85,
                            "borrowCapacityUSD": 3000,
                            "balanceData": {
                              "deposits": 10000.5,
                              "debt": 5000.25,
                              "adjustedDebt": 5500,
                              "collateral": 9000,
                              "collateralAllActive": 10000.5,
                              "borrowDiscountedCollateral": 8000,
                              "borrowDiscountedCollateralAllActive": 9000,
                              "nav": 5000.25,
                              "deposits24h": 9800,
                              "debt24h": 4900,
                              "nav24h": 4900,
                              "rewards": [
                                {
                                  "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                                  "totalRewards": 12.5,
                                  "claimableRewards": 12.5
                                }
                              ]
                            },
                            "aprData": {
                              "apr": 2.5,
                              "depositApr": 3.5,
                              "borrowApr": 5.2,
                              "rewardApr": 1.2,
                              "rewardDepositApr": 0.8,
                              "rewardBorrowApr": 0.4,
                              "intrinsicApr": 0,
                              "intrinsicDepositApr": 0,
                              "intrinsicBorrowApr": 0,
                              "rewards": {}
                            },
                            "positions": [
                              {
                                "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                                "deposits": "1000000000000000000",
                                "debt": "0",
                                "debtStable": "0",
                                "debtShares": "0",
                                "depositShares": "0",
                                "depositsUSD": 2500,
                                "debtUSD": 0,
                                "debtStableUSD": 0,
                                "depositsUSDOracle": 2510,
                                "debtUSDOracle": 0,
                                "debtStableUSDOracle": 0,
                                "collateralEnabled": true,
                                "claimableRewards": 0.5,
                                "withdrawable": "0.5",
                                "borrowable": "100",
                                "underlyingInfo": {
                                  "asset": {},
                                  "oraclePrice": {},
                                  "prices": {}
                                },
                                "loanId": "450",
                                "term": {
                                  "loanId": "450",
                                  "termId": 2,
                                  "isDynamic": false,
                                  "debt": "14.5003",
                                  "apr": 3.85,
                                  "maturity": 1781789025,
                                  "termDays": 7,
                                  "accruedInterest": "0.000358",
                                  "earlyRepayPenalty": "0.001211",
                                  "isMatured": false,
                                  "faceValue": "100.0",
                                  "earlyRepayDiscount": "1.0",
                                  "latePenalty": "2.25",
                                  "latePenaltyPerDay": "0.225",
                                  "latePenaltyApr": 164.24,
                                  "secondsLate": 0
                                }
                              }
                            ],
                            "userConfig": {
                              "selectedMode": "0",
                              "id": "0",
                              "isWhitelisted": true
                            }
                          }
                        ],
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        },
                        "leverage": 2
                      }
                    ],
                    "summary": {
                      "balanceData": {
                        "deposits": 10000.5,
                        "debt": 5000.25,
                        "collateral": 9000,
                        "collateralAllActive": 10000.5,
                        "nav": 5000.25,
                        "deposits24h": 9800,
                        "debt24h": 4900,
                        "nav24h": 4900,
                        "rewards": [
                          {
                            "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                            "totalRewards": 12.5,
                            "claimableRewards": 12.5
                          }
                        ]
                      },
                      "aprData": {
                        "apr": 2.5,
                        "depositApr": 3.5,
                        "borrowApr": 5.2,
                        "rewardApr": 1.2,
                        "rewardDepositApr": 0.8,
                        "rewardBorrowApr": 0.4,
                        "intrinsicApr": 0,
                        "intrinsicDepositApr": 0,
                        "intrinsicBorrowApr": 0,
                        "rewards": {}
                      },
                      "leverage": 2,
                      "activeLenders": 3,
                      "activeChains": 2
                    },
                    "partial": true,
                    "incompleteLenders": [
                      "1:AAVE_V3",
                      "1:COMPOUND_V3_USDC"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "$comment": "Without an explicit id this collides with the 'User Positions' tag route and falls back to the path-derived 'get-v1-data-lending-user-positions'.",
        "operationId": "lending-user-positions"
      }
    },
    "/v1/data/lending/user-positions/rpc-call": {
      "get": {
        "tags": [
          "User Positions"
        ],
        "summary": "User position RPC calls",
        "description": "Prepares raw JSON-RPC calls (using multicall3 aggregate3) for fetching user lending positions on a single chain. Returns an `rpcCallId` and an array of `rpcCalls` that the integrator executes against their own RPC provider. The raw responses are then submitted to `/parse` together with the `rpcCallId`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/user-positions/rpc-call`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) |\n| `chain` | query | string | yes | Chain ID to query |\n| `lenders` | query | string | no | Comma-separated lender IDs to filter by. If omitted, all supported lenders for the chain are included. See the `LenderId` schema for the full set of accepted values. |\n| `batchSize` | query | integer | no | Max number of sub-calls per multicall batch |\n| `blockTag` | query | string | no | Block tag for the RPC calls |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.data.rpcCallId` | string | Unique ID referencing the server-side cached context. Pass this to /parse together with the raw responses. Valid for 5 minutes. |\n| `data.data.rpcCalls` | object[] | Ordered list of JSON-RPC calls to execute against the target chain RPC. Each call uses multicall3 aggregate3. |\n| `data.data.rpcCalls[].method` | string | JSON-RPC method name |\n| `data.data.rpcCalls[].params` | any[] | JSON-RPC parameters (call object and block tag) |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"data\": {\n      \"rpcCallId\": \"string\",\n      \"rpcCalls\": [\n        {\n          \"method\": \"eth_call\",\n          \"params\": []\n        }\n      ]\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
            },
            "description": "EVM account address (0x-prefixed, 40 hex chars)",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to query",
            "example": "1"
          },
          {
            "name": "lenders",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3,COMPOUND_V3_WETH"
            },
            "description": "Comma-separated lender IDs to filter by. If omitted, all supported lenders for the chain are included. See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3,COMPOUND_V3_WETH"
          },
          {
            "name": "batchSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4096,
              "example": 4096
            },
            "description": "Max number of sub-calls per multicall batch",
            "example": 4096
          },
          {
            "name": "blockTag",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "latest",
              "example": "latest"
            },
            "description": "Block tag for the RPC calls",
            "example": "latest"
          }
        ],
        "responses": {
          "200": {
            "description": "Prepared RPC calls with a context ID for parsing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/RpcCallResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "data": {
                      "rpcCallId": "string",
                      "rpcCalls": [
                        {
                          "method": "eth_call",
                          "params": []
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "user-position-rpc-calls"
      }
    },
    "/v1/data/lending/user-positions/parse": {
      "post": {
        "tags": [
          "User Positions"
        ],
        "summary": "Parse user positions",
        "description": "Accepts the raw multicall RPC responses obtained by executing the calls from `/rpc-call` and decodes them into structured user position data.\n\n**Workflow:**\n1. Call `/rpc-call` to get prepared RPC calls and a `rpcCallId`\n2. Execute the RPC calls against your own node\n3. Send `rpcCallId` + `rawResponses` to this endpoint for parsing\n\nThe `rpcCallId` ties the responses back to the cached preparation context (valid for 5 minutes).\nAfter successful parsing the cached context is deleted.\n\n**Response Structure:**\n- `items`: Flat array of lender entries sorted by net worth (descending). Each entry fuses sub-account position data with aggregated summary metrics (deposits, debt, APRs, health, leverage).\n- `summary`: Portfolio-wide totals (net worth, APRs, leverage, active counts) plus per-chain breakdowns.\n\n**Lender Entry includes:**\n- Per-asset deposits and debt (in USD and token units)\n- Sub-account data with health factors and borrow capacity\n- Aggregated lender-level metrics (total deposits/debt, weighted APRs, health factor, leverage)\n- Collateral status, withdrawable/borrowable amounts per position\n\n**Portfolio Summary includes:**\n- Total deposits, debt, and net worth (current + 24h ago) across all chains\n- Weighted average APRs and overall leverage ratio\n- Count of active lenders and chains\n- Per-chain totals (deposits, debt, net worth, lender count)\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/lending/user-positions/parse`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `rpcCallId` | string | yes | The rpcCallId returned by /rpc-call. |\n| `rawResponses` | object[] | yes | Raw JSON-RPC response results in the same order as the rpcCalls array. Each entry is the hex-encoded result of the corresponding multicall3 aggregate3 call. |\n| `rawResponses[].result` | string | no | Hex-encoded result data |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | User lending positions as a flat array with portfolio summary and per-chain breakdowns. |\n| `data.items` | object[] | Flat array of lender entries sorted by net worth (descending). Each entry fuses position data with aggregated summary metrics. |\n| `data.items[].lender` | string | Lender identifier |\n| `data.items[].chainId` | string | Chain ID |\n| `data.items[].account` | string | User account address |\n| `data.items[].data` | object[] | Sub-account position data |\n| `data.items[].data[].accountId` | string | Sub-account identifier (e.g., \"0\" for default, NFT ID for Init) |\n| `data.items[].data[].health` | number | Health factor (null if no debt). Values > 1 are healthy, < 1 at risk of liquidation. |\n| `data.items[].data[].borrowCapacityUSD` | number | Total USD borrowable while maintaining health >= 1 |\n| `data.items[].data[].balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.items[].data[].aprData` | object | APR breakdown for a sub-account. |\n| `data.items[].data[].positions` | object[] | Individual asset positions in this sub-account |\n| `data.items[].data[].userConfig` | object | User configuration for a sub-account. |\n| `data.items[].balanceData` | object | Summary-level balance data (without discounted/adjusted fields). |\n| `data.items[].balanceData.deposits` | number | Total deposits in USD |\n| `data.items[].balanceData.debt` | number | Total debt in USD |\n| `data.items[].balanceData.collateral` | number | Collateral value in USD |\n| `data.items[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled |\n| `data.items[].balanceData.nav` | number | Net asset value (deposits - debt) |\n| `data.items[].balanceData.deposits24h` | number | Deposits 24h ago |\n| `data.items[].balanceData.debt24h` | number | Debt 24h ago |\n| `data.items[].balanceData.nav24h` | number | NAV 24h ago |\n| `data.items[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. |\n| `data.items[].aprData` | object | Summary-level APR breakdown. |\n| `data.items[].aprData.apr` | number | Net APR (deposit - borrow) |\n| `data.items[].aprData.depositApr` | number | Weighted deposit APR |\n| `data.items[].aprData.borrowApr` | number | Weighted borrow APR |\n| `data.items[].aprData.rewardApr` | number | Total reward APR |\n| `data.items[].aprData.rewardDepositApr` | number | Reward APR on deposits |\n| `data.items[].aprData.rewardBorrowApr` | number | Reward APR on borrows |\n| `data.items[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) |\n| `data.items[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits |\n| `data.items[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows |\n| `data.items[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `data.items[].leverage` | number | Leverage ratio (deposits / nav) |\n| `data.summary` | object | Portfolio-wide totals with per-chain breakdowns. Per-lender summaries are fused into each LenderDataEntry in the items array. |\n| `data.summary.balanceData` | object | Summary-level balance data (without discounted/adjusted fields). |\n| `data.summary.balanceData.deposits` | number | Total deposits in USD |\n| `data.summary.balanceData.debt` | number | Total debt in USD |\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParseUserDataRequest"
              },
              "example": {
                "rpcCallId": "string",
                "rawResponses": [
                  {
                    "result": "string"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed user position data with portfolio summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/UserPositionResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "lender": "AAVE_V3",
                        "chainId": "1",
                        "account": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5",
                        "data": [
                          {
                            "accountId": "0",
                            "health": 1.85,
                            "borrowCapacityUSD": 3000,
                            "balanceData": {
                              "deposits": 10000.5,
                              "debt": 5000.25,
                              "adjustedDebt": 5500,
                              "collateral": 9000,
                              "collateralAllActive": 10000.5,
                              "borrowDiscountedCollateral": 8000,
                              "borrowDiscountedCollateralAllActive": 9000,
                              "nav": 5000.25,
                              "deposits24h": 9800,
                              "debt24h": 4900,
                              "nav24h": 4900,
                              "rewards": [
                                {
                                  "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                                  "totalRewards": 12.5,
                                  "claimableRewards": 12.5
                                }
                              ]
                            },
                            "aprData": {
                              "apr": 2.5,
                              "depositApr": 3.5,
                              "borrowApr": 5.2,
                              "rewardApr": 1.2,
                              "rewardDepositApr": 0.8,
                              "rewardBorrowApr": 0.4,
                              "intrinsicApr": 0,
                              "intrinsicDepositApr": 0,
                              "intrinsicBorrowApr": 0,
                              "rewards": {}
                            },
                            "positions": [
                              {
                                "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                                "deposits": "1000000000000000000",
                                "debt": "0",
                                "debtStable": "0",
                                "debtShares": "0",
                                "depositShares": "0",
                                "depositsUSD": 2500,
                                "debtUSD": 0,
                                "debtStableUSD": 0,
                                "depositsUSDOracle": 2510,
                                "debtUSDOracle": 0,
                                "debtStableUSDOracle": 0,
                                "collateralEnabled": true,
                                "claimableRewards": 0.5,
                                "withdrawable": "0.5",
                                "borrowable": "100",
                                "underlyingInfo": {
                                  "asset": {},
                                  "oraclePrice": {},
                                  "prices": {}
                                },
                                "loanId": "450",
                                "term": {
                                  "loanId": "450",
                                  "termId": 2,
                                  "isDynamic": false,
                                  "debt": "14.5003",
                                  "apr": 3.85,
                                  "maturity": 1781789025,
                                  "termDays": 7,
                                  "accruedInterest": "0.000358",
                                  "earlyRepayPenalty": "0.001211",
                                  "isMatured": false,
                                  "faceValue": "100.0",
                                  "earlyRepayDiscount": "1.0",
                                  "latePenalty": "2.25",
                                  "latePenaltyPerDay": "0.225",
                                  "latePenaltyApr": 164.24,
                                  "secondsLate": 0
                                }
                              }
                            ],
                            "userConfig": {
                              "selectedMode": "0",
                              "id": "0",
                              "isWhitelisted": true
                            }
                          }
                        ],
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        },
                        "leverage": 2
                      }
                    ],
                    "summary": {
                      "balanceData": {
                        "deposits": 10000.5,
                        "debt": 5000.25,
                        "collateral": 9000,
                        "collateralAllActive": 10000.5,
                        "nav": 5000.25,
                        "deposits24h": 9800,
                        "debt24h": 4900,
                        "nav24h": 4900,
                        "rewards": [
                          {
                            "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                            "totalRewards": 12.5,
                            "claimableRewards": 12.5
                          }
                        ]
                      },
                      "aprData": {
                        "apr": 2.5,
                        "depositApr": 3.5,
                        "borrowApr": 5.2,
                        "rewardApr": 1.2,
                        "rewardDepositApr": 0.8,
                        "rewardBorrowApr": 0.4,
                        "intrinsicApr": 0,
                        "intrinsicDepositApr": 0,
                        "intrinsicBorrowApr": 0,
                        "rewards": {}
                      },
                      "leverage": 2,
                      "activeLenders": 3,
                      "activeChains": 2
                    },
                    "partial": true,
                    "incompleteLenders": [
                      "1:AAVE_V3",
                      "1:COMPOUND_V3_USDC"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "404": {
            "description": "RPC call context not found or expired (older than 5 minutes). Call `/rpc-call` again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "parse-user-positions"
      }
    },
    "/v1/data/prices/latest": {
      "get": {
        "tags": [
          "Prices"
        ],
        "summary": "Get latest prices",
        "description": "Returns latest USD prices for tracked assets.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/prices/latest`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `assets` | query | string[] | no | Asset group keys (repeatable) |\n| `asOf` | query | string | no | ISO date anchor; defaults to latest hour |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.asOf` | string | Timestamp the data was measured at. |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object | Map of asset_group → priceUsd |\n| `data.debug` | object |  |\n| `data.debug.rows` | object[] |  |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"asOf\": \"2026-01-01T00:00:00Z\",\n    \"count\": 1,\n    \"items\": {\n      \"USDC\": 1.0001,\n      \"WBTC\": 67432.12\n    },\n    \"debug\": {\n      \"rows\": [\n        {}\n      ]\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "assets",
            "in": "query",
            "description": "Asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          },
          {
            "name": "asOf",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-01-15T12:00:00Z"
            },
            "description": "ISO date anchor; defaults to latest hour",
            "example": "2025-01-15T12:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Latest price data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/PriceResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "asOf": "2026-01-01T00:00:00Z",
                    "count": 1,
                    "items": {
                      "USDC": 1.0001,
                      "WBTC": 67432.12
                    },
                    "debug": {
                      "rows": [
                        {}
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-latest-prices"
      }
    },
    "/v1/data/prices/latest-asof": {
      "get": {
        "tags": [
          "Prices"
        ],
        "summary": "Get prices as of X hours ago",
        "description": "Returns prices at an effective cutoff time computed as `asOf − hoursAgo`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/prices/latest-asof`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `hoursAgo` | query | number | yes | Non-negative number of hours in the past |\n| `asOf` | query | string | no | ISO date anchor; defaults to now |\n| `assetGroups` | query | string[] | no | Asset group keys (repeatable) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.asOf` | string | Timestamp the data was measured at. |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object | Map of asset_group → priceUsd |\n| `data.debug` | object |  |\n| `data.debug.rows` | object[] |  |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"asOf\": \"2026-01-01T00:00:00Z\",\n    \"count\": 1,\n    \"items\": {\n      \"USDC\": 1.0001,\n      \"WBTC\": 67432.12\n    },\n    \"debug\": {\n      \"rows\": [\n        {}\n      ]\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "hoursAgo",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 24
            },
            "description": "Non-negative number of hours in the past",
            "example": 24
          },
          {
            "name": "asOf",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-01-15T12:00:00Z"
            },
            "description": "ISO date anchor; defaults to now",
            "example": "2025-01-15T12:00:00Z"
          },
          {
            "name": "assetGroups",
            "in": "query",
            "description": "Asset group keys (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "ETH",
                "USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "ETH",
              "USDC"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Prices at the effective cutoff time",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/PriceResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "asOf": "2026-01-01T00:00:00Z",
                    "count": 1,
                    "items": {
                      "USDC": 1.0001,
                      "WBTC": 67432.12
                    },
                    "debug": {
                      "rows": [
                        {}
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-prices-as-of-x-hours-ago"
      }
    },
    "/v1/data/health": {
      "get": {
        "tags": [
          "General"
        ],
        "summary": "Health check",
        "description": "Returns service health status.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/health`</summary>\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.latestHour` | string | Latest data generation hour |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"latestHour\": \"2026-01-01T00:00:00Z\"\n  }\n}\n```\n\n</details>\n",
        "responses": {
          "200": {
            "description": "Service health",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/HealthResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "latestHour": "2026-01-01T00:00:00Z"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "health-check"
      }
    },
    "/v1/data/rpcs": {
      "get": {
        "tags": [
          "General"
        ],
        "summary": "Get RPC endpoints for chains",
        "description": "Returns RPC URLs for the requested chains.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/rpcs`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chains` | query | string[] | yes | Chain IDs to fetch RPCs for (repeatable) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Chain ID to array of RPC URLs. Keys are chain IDs; values are arrays of RPC endpoint URLs. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chains",
            "in": "query",
            "required": true,
            "description": "Chain IDs to fetch RPCs for (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "10"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "10"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "RPC endpoints for requested chains",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/RpcsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "404": {
            "description": "None of the requested chains exist in the data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-rpc-endpoints-for-chains"
      }
    },
    "/v1/data/chains": {
      "get": {
        "tags": [
          "General"
        ],
        "summary": "Get supported chains",
        "description": "Returns every supported chain with its id, display name and logo. Chain ids are decimal **strings**, not numbers. Also published as the `ChainId` schema so it can be code-generated.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/chains`</summary>\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of supported chains |\n| `data.items` | object[] | Supported chains, sorted ascending by numeric chainId. |\n| `data.items[].chainId` | string | Decimal EVM chain id, as a string. |\n| `data.items[].name` | string | Human-readable display name. Prefers the registry `shortName` (concise, e.g. \"eth\"); falls back to the long `name`, then to \"Chain {id}\". |\n| `data.items[].logoURI` | string | Absolute URL to the chain icon. Always populated; consumers should handle broken images gracefully. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": [\n      {\n        \"chainId\": \"1\",\n        \"name\": \"eth\",\n        \"logoURI\": \"https://raw.githubusercontent.com/1delta-DAO/chains/main/1.webp\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "responses": {
          "200": {
            "description": "Supported chains",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/ChainsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "chainId": "1",
                        "name": "eth",
                        "logoURI": "https://raw.githubusercontent.com/1delta-DAO/chains/main/1.webp"
                      }
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-supported-chains"
      }
    },
    "/v1/data/lender-ids": {
      "get": {
        "tags": [
          "General"
        ],
        "summary": "Get lender IDs",
        "description": "Returns every supported protocol identifier as a flat array of strings. These are the values accepted by the `lender` query parameter and used as the first segment of a `marketUid`. Also published as the `LenderId` schema so it can be code-generated.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lender-ids`</summary>\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | string[] | Sorted list of supported lender protocol identifiers. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    \"AAVE_V2\",\n    \"AAVE_V3\",\n    \"COMPOUND_V2\",\n    \"COMPOUND_V3_USDC\",\n    \"EULER_V2\",\n    \"INIT\",\n    \"LISTA\",\n    \"MORPHO\",\n    \"SPARK\",\n    \"VENUS\"\n  ]\n}\n```\n\n</details>\n",
        "responses": {
          "200": {
            "description": "Lender IDs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LenderIdsResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": [
                    "AAVE_V2",
                    "AAVE_V3",
                    "COMPOUND_V2",
                    "COMPOUND_V3_USDC",
                    "EULER_V2",
                    "INIT",
                    "LISTA",
                    "MORPHO",
                    "SPARK",
                    "VENUS"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-lender-ids"
      }
    },
    "/v1/data/snapshots": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get lending snapshots",
        "description": "Returns historical lending data time series for specified markets.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/snapshots`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUids` | query | string[] | yes | Market UIDs (repeatable) |\n| `fields` | query | `depositRate`, `variableBorrowRate`, `stableBorrowRate`, `totalDeposits`, `totalDebtStable`, `totalDebt`, … (11 values)[] | no | Fields to include in each snapshot point (repeatable) |\n| `start` | query | string | no | ISO start date |\n| `end` | query | string | no | ISO end date |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.markets` | integer | Number of distinct markets |\n| `data.totalPoints` | integer | Total data points across all markets |\n| `data.series` | object | Map of marketUid → array of {dataTs, ...fields} |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"markets\": 1,\n    \"totalPoints\": 1,\n    \"series\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUids",
            "in": "query",
            "required": true,
            "description": "Market UIDs (repeatable)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            ]
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Fields to include in each snapshot point (repeatable)",
            "example": [
              "depositRate",
              "variableBorrowRate"
            ],
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "depositRate",
                  "variableBorrowRate",
                  "stableBorrowRate",
                  "totalDeposits",
                  "totalDebtStable",
                  "totalDebt",
                  "totalLiquidity",
                  "totalDepositsUsd",
                  "totalDebtStableUsd",
                  "totalDebtUsd",
                  "totalLiquidityUsd"
                ]
              },
              "example": [
                "depositRate",
                "variableBorrowRate"
              ]
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-01T00:00:00Z"
            },
            "description": "ISO start date",
            "example": "2025-11-01T00:00:00Z"
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "2025-11-15T00:00:00Z"
            },
            "description": "ISO end date",
            "example": "2025-11-15T00:00:00Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Lending snapshot data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/LendingSnapshotResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "markets": 1,
                    "totalPoints": 1,
                    "series": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-lending-snapshots"
      }
    },
    "/v1/data/sparklines": {
      "post": {
        "tags": [
          "Prices"
        ],
        "summary": "Sparkline price-ratio time series",
        "description": "Returns price-ratio time series for the cross product of `currencies` × `quotes` over a configurable lookback window (default 24h).\n\n**Request body:** `{ currencies: string[], quotes: string[], windowHours?: number }` where each ID is either a shorthand (`\"usd\"`, `\"eth\"`) or `\"{chainId}-{address}\"`. See the `SparklineRequest` schema.\n\n**Response:** `{ windowHours, count, result }`. Each `result[i]` has `{ currency, quote, data }` where `data` is an array of `{ time, value }` points and `value = price(currency) / price(quote)`. Pairs with no data are omitted from `result` (so `count` ≤ `currencies.length × quotes.length`).\n\nUseful for rendering small inline charts (token cards, asset selectors) without hitting the heavier snapshot endpoints.\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/sparklines`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `currencies` | string[] | yes | Currency identifiers. Use shorthand (\"usd\", \"eth\") or \"{chainId}-{address}\" format. |\n| `quotes` | string[] | yes | Quote identifiers (same format as currencies) |\n| `windowHours` | number | no | Lookback window in hours |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.windowHours` | number |  |\n| `data.count` | integer | Number of non-empty sparkline pairs |\n| `data.result` | object[] |  |\n| `data.result[].currency` | string |  |\n| `data.result[].quote` | string |  |\n| `data.result[].data` | object[] | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.result[].data[].value` | number | Price ratio (currency / quote) |\n| `data.result[].data[].time` | string |  |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"windowHours\": 1.0,\n    \"count\": 1,\n    \"result\": [\n      {\n        \"currency\": \"string\",\n        \"quote\": \"string\",\n        \"data\": [\n          {\n            \"value\": 1.0,\n            \"time\": \"2026-01-01T00:00:00Z\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SparklineRequest"
              },
              "example": {
                "currencies": [
                  "string"
                ],
                "quotes": [
                  "string"
                ],
                "windowHours": 24
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sparkline data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/SparklineResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "windowHours": 1,
                    "count": 1,
                    "result": [
                      {
                        "currency": "string",
                        "quote": "string",
                        "data": [
                          {
                            "value": 1,
                            "time": "2026-01-01T00:00:00Z"
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "sparkline-price-ratio-time-series"
      }
    },
    "/v1/data/meta/lending/complete": {
      "get": {
        "tags": [
          "General"
        ],
        "summary": "Complete lending metadata",
        "description": "Returns the full lending-protocol metadata bundle for the requested chains and lenders. This is the single source of truth for static lender/chain/market configuration consumed by the SDKs and the position-builder UI.\n\n**Response includes**, per `(chainId, lenderKey)`:\n- Supported markets and their underlying assets (address, symbol, decimals, asset group)\n- Per-market risk parameters (LTV, liquidation threshold, factor, mode/e-mode IDs)\n- Pool configuration IDs and which markets are eligible as collateral / borrowable per config\n- Protocol contract addresses (pool, oracle, IRM, composer wiring)\n\nFilter with `chainIds` and/or `lenders` to keep payloads small — both filters are AND-combined.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/meta/lending/complete`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. |\n| `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of entries in `items`. |\n| `data.items` | object | The result set for this response. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainIds",
            "in": "query",
            "description": "Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "42161"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "42161"
            ]
          },
          {
            "name": "lenders",
            "in": "query",
            "description": "Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "AAVE_V3",
                "COMPOUND_V3_USDC"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "AAVE_V3",
              "COMPOUND_V3_USDC"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Lending metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MetaLendingCompleteResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "complete-lending-metadata"
      }
    },
    "/v1/data/lending/isolated-markets/meta": {
      "get": {
        "tags": [
          "Lending (Data)"
        ],
        "summary": "Get isolated market metadata",
        "description": "Returns Morpho isolated market metadata including fee, LLTV, oracle, IRM, and listing status for all markets, optionally filtered by chain.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/lending/isolated-markets/meta`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainIds",
            "in": "query",
            "description": "Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": [
                "1",
                "8453"
              ]
            },
            "style": "form",
            "explode": true,
            "example": [
              "1",
              "8453"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Isolated market metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-isolated-market-metadata"
      }
    },
    "/v1/data/token/list": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Get token list for a chain",
        "description": "Fetches the complete token list for a given chain, including metadata such as symbol, name, decimals, and asset group.\n\n**Response Structure:**\n- `tokens`: Object keyed by token address (lowercase) containing token metadata\n- `count`: Total number of tokens in the list\n\n**Token Metadata includes:**\n- `symbol`: Token symbol (e.g., \"USDC\")\n- `name`: Full token name (e.g., \"USD Coin\")\n- `decimals`: Token decimals (e.g., 6 for USDC)\n- `assetGroup`: Asset grouping for price lookups\n- `logoURI`: Optional logo URL\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/list`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID to fetch token list for See the `ChainId` schema for the full set of supported chains. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.count` | integer | Total number of tokens |\n| `data.tokens` | object | Map of token address (lowercase) → token metadata |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainId\": \"1\",\n    \"count\": 1,\n    \"tokens\": {}\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to fetch token list for See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "Token list for the chain",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenListResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "chainId": "1",
                    "count": 1,
                    "tokens": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-token-list-for-a-chain"
      }
    },
    "/v1/data/bridge/status": {
      "get": {
        "tags": [
          "Data › Bridge"
        ],
        "summary": "Bridge transfer status",
        "description": "Tracks a bridge transfer started via `/v1/actions/swap/x-chain` by polling the bridge's own tracking API. `status` is one of `PENDING`, `DONE`, `FAILED`, `TRANSFER_REFUNDED`, `INVALID`, `NOT_FOUND`, `PARTIAL_SUCCESS`. `NOT_FOUND` is normal in the first seconds after submission (indexer lag) — keep polling. `toHash` is the destination-chain transaction when the tracker exposes it. Responses are not cached.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/bridge/status`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `bridge` | query | string | yes | The `bridge` value from the executed quote |\n| `fromChainId` | query | string | yes | Source chain ID of the transfer |\n| `toChainId` | query | string | yes | Destination chain ID |\n| `txHash` | query | string | no | Source-chain transaction hash of the executed bridge transaction (required unless `orderId`) |\n| `tokenIn` | query | string | no | Bridged input token address — REQUIRED for Stargate (pool-keyed tracker), ignored by most bridges |\n| `tokenOut` | query | string | no | Bridged output token address — REQUIRED for Stargate |\n| `orderId` | query | string | no | Intent order id for order-based bridges (Mayan) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | boolean |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.bridge` | string |  |\n| `data.status` | `PENDING`, `DONE`, `FAILED`, `TRANSFER_REFUNDED`, `INVALID`, `NOT_FOUND`, … (7 values) |  |\n| `data.message` | string |  |\n| `data.fromHash` | string |  |\n| `data.toHash` | string | Destination-chain tx hash when known |\n| `data.details` | object | The tracker's raw response payload |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"bridge\": \"string\",\n    \"status\": \"PENDING\",\n    \"message\": \"string\",\n    \"fromHash\": \"string\",\n    \"toHash\": \"string\"\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "bridge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "Across"
            },
            "description": "The `bridge` value from the executed quote",
            "example": "Across"
          },
          {
            "name": "fromChainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Source chain ID of the transfer",
            "example": "1"
          },
          {
            "name": "toChainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "8453"
            },
            "description": "Destination chain ID",
            "example": "8453"
          },
          {
            "name": "txHash",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Source-chain transaction hash of the executed bridge transaction (required unless `orderId`)"
          },
          {
            "name": "tokenIn",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Bridged input token address — REQUIRED for Stargate (pool-keyed tracker), ignored by most bridges"
          },
          {
            "name": "tokenOut",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Bridged output token address — REQUIRED for Stargate"
          },
          {
            "name": "orderId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Intent order id for order-based bridges (Mayan)"
          }
        ],
        "responses": {
          "200": {
            "description": "Transfer status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "bridge": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "DONE",
                            "FAILED",
                            "TRANSFER_REFUNDED",
                            "INVALID",
                            "NOT_FOUND",
                            "PARTIAL_SUCCESS"
                          ]
                        },
                        "message": {
                          "type": "string"
                        },
                        "fromHash": {
                          "type": "string"
                        },
                        "toHash": {
                          "type": "string",
                          "description": "Destination-chain tx hash when known"
                        },
                        "details": {
                          "nullable": true,
                          "description": "The tracker's raw response payload"
                        }
                      },
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "bridge": "string",
                    "status": "PENDING",
                    "message": "string",
                    "fromHash": "string",
                    "toHash": "string"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "bridge-transfer-status"
      }
    },
    "/v1/data/token/balances": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Token balances",
        "description": "Fetches token balances for a given account on a specific chain, including USD values.\n\n**Features:**\n- Automatically includes native token balance (ETH, BNB, etc.)\n- Fetches current prices for USD conversion\n- Returns both raw and formatted balance values\n\n**Response Structure:**\n- `items`: Array of balance entries for each token\n- `count`: Total number of balance entries\n\n**Balance Entry includes:**\n- `address`: Token contract address (zeroAddress for native)\n- `symbol`: Token symbol\n- `name`: Token name\n- `decimals`: Token decimals\n- `balanceRaw`: Raw balance as string (wei/smallest unit)\n- `balance`: Formatted balance as decimal string\n- `balanceUSD`: Balance value in USD\n\n**Note:** The native token balance is always included with address `0x0000000000000000000000000000000000000000`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/balances`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) |\n| `assets` | query | string | yes | Comma-separated token addresses to fetch balances for |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.account` | string | Lowercase account address |\n| `data.count` | integer | Number of balance entries |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].address` | string | Token contract address (zeroAddress for native) |\n| `data.items[].symbol` | string | Token symbol, e.g. `WETH`. |\n| `data.items[].name` | string | Human-readable display name. |\n| `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. |\n| `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) |\n| `data.items[].balance` | string | Formatted balance as decimal string |\n| `data.items[].priceUSD` | number | Per-unit USD price of the token |\n| `data.items[].balanceUSD` | number | Balance value in USD |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainId\": \"1\",\n    \"account\": \"0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5\",\n    \"count\": 1,\n    \"items\": [\n      {\n        \"address\": \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n        \"symbol\": \"USDC\",\n        \"name\": \"USD Coin\",\n        \"decimals\": 6,\n        \"balanceRaw\": \"1000000\",\n        \"balance\": \"1.0\",\n        \"priceUSD\": 1,\n        \"balanceUSD\": 1\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
            },
            "description": "EVM account address (0x-prefixed, 40 hex chars)",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          {
            "name": "assets",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
            },
            "description": "Comma-separated token addresses to fetch balances for",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
          }
        ],
        "responses": {
          "200": {
            "description": "Token balances with USD values",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenBalancesResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "chainId": "1",
                    "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5",
                    "count": 1,
                    "items": [
                      {
                        "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                        "symbol": "USDC",
                        "name": "USD Coin",
                        "decimals": 6,
                        "balanceRaw": "1000000",
                        "balance": "1.0",
                        "priceUSD": 1,
                        "balanceUSD": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "token-balances"
      }
    },
    "/v1/data/token/balances/rpc-call": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Token balance RPC calls",
        "description": "Prepares raw JSON-RPC `eth_call`s for fetching token balances using a batched balance-fetcher contract. Returns an `rpcCallId` and an array of `rpcCalls` that the integrator executes against their own RPC provider(s). The raw responses are then submitted to `/token/balances/parse` together with the `rpcCallId`. Two modes: **single-chain** (`chainId` + required `assets`; `rpcCalls` is a bare call array) and **multi-chain** (`chains` CSV, max 30; `rpcCalls` entries are `{ chainId, call }`). In multi-chain mode `assets` is optional — it defaults to each chain's curated `mainTokens` from the token lists, keeping balance scans small even where full lists hold tens of thousands of tokens (max 200 assets per chain). Chains without any known main tokens are reported in `skippedChains`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/balances/rpc-call`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Chain ID to fetch balances on (single-chain mode; required unless `chains` is given) See the `ChainId` schema for the full set of supported chains. |\n| `chains` | query | string | no | Comma-separated chain IDs (multi-chain mode, max 30). Takes precedence over `chainId`. |\n| `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) |\n| `assets` | query | string | no | Comma-separated token addresses. Required in single-chain mode; optional in multi-chain mode (defaults to each chain’s `mainTokens`; when given, applied to every chain). |\n| `blockTag` | query | string | no | Block tag for the RPC call |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.data.rpcCallId` | string | Unique ID referencing the server-side cached context. Pass this to /parse together with the raw responses. Valid for 5 minutes. |\n| `data.data.rpcCalls` | object[] | Ordered list of JSON-RPC calls to execute against the target chain RPC. Each call uses multicall3 aggregate3. |\n| `data.data.rpcCalls[].method` | string | JSON-RPC method name |\n| `data.data.rpcCalls[].params` | any[] | JSON-RPC parameters (call object and block tag) |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"data\": {\n      \"rpcCallId\": \"string\",\n      \"rpcCalls\": [\n        {\n          \"method\": \"eth_call\",\n          \"params\": []\n        }\n      ]\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to fetch balances on (single-chain mode; required unless `chains` is given) See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "chains",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,10,8453"
            },
            "description": "Comma-separated chain IDs (multi-chain mode, max 30). Takes precedence over `chainId`.",
            "example": "1,10,8453"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
            },
            "description": "EVM account address (0x-prefixed, 40 hex chars)",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          {
            "name": "assets",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
            },
            "description": "Comma-separated token addresses. Required in single-chain mode; optional in multi-chain mode (defaults to each chain’s `mainTokens`; when given, applied to every chain).",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
          },
          {
            "name": "blockTag",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "latest",
              "example": "latest"
            },
            "description": "Block tag for the RPC call",
            "example": "latest"
          }
        ],
        "responses": {
          "200": {
            "description": "Prepared RPC calls with a context ID for parsing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/RpcCallResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "data": {
                      "rpcCallId": "string",
                      "rpcCalls": [
                        {
                          "method": "eth_call",
                          "params": []
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "token-balance-rpc-calls"
      }
    },
    "/v1/data/token/balances/parse": {
      "post": {
        "tags": [
          "Token"
        ],
        "summary": "Parse token balances",
        "description": "Accepts the raw hex RPC response obtained by executing the call from `/token/balances/rpc-call` and decodes it into structured token balance data with USD values.\n\n**Workflow:**\n1. Call `/token/balances/rpc-call` to get prepared RPC calls and a `rpcCallId`\n2. Execute the RPC call against your own node\n3. Send `rpcCallId` + `rawResponses` to this endpoint for parsing\n\nThe `rpcCallId` ties the response back to the cached preparation context (valid for 5 minutes).\nAfter successful parsing the cached context is deleted.\n\n**Multi-chain mode** (when the rpc-call was made with `chains`): `rawResponses` entries are\n`{ chainId, result }` (result = hex string or full JSON-RPC envelope), and the response is\n`{ account, chains: [{ chainId, count, items }], missingChains? }` — chains whose response was\nnot submitted appear in `missingChains`.\n\n**Response Structure:**\n- `items`: Array of balance entries for each token\n- `count`: Total number of balance entries\n\n**Balance Entry includes:**\n- `address`: Token contract address (zeroAddress for native)\n- `symbol`: Token symbol\n- `name`: Token name\n- `decimals`: Token decimals\n- `balanceRaw`: Raw balance as string (wei/smallest unit)\n- `balance`: Formatted balance as decimal string\n- `balanceUSD`: Balance value in USD\n\n<details>\n<summary>Plain-text reference — `POST /v1/data/token/balances/parse`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `rpcCallId` | string | yes | The rpcCallId returned by /token/balances/rpc-call. |\n| `rawResponses` | string[] | yes | Array containing the raw hex-encoded result from the eth_call. Typically a single-element array. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.account` | string | Lowercase account address |\n| `data.count` | integer | Number of balance entries |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].address` | string | Token contract address (zeroAddress for native) |\n| `data.items[].symbol` | string | Token symbol, e.g. `WETH`. |\n| `data.items[].name` | string | Human-readable display name. |\n| `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. |\n| `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) |\n| `data.items[].balance` | string | Formatted balance as decimal string |\n| `data.items[].priceUSD` | number | Per-unit USD price of the token |\n| `data.items[].balanceUSD` | number | Balance value in USD |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainId\": \"1\",\n    \"account\": \"0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5\",\n    \"count\": 1,\n    \"items\": [\n      {\n        \"address\": \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n        \"symbol\": \"USDC\",\n        \"name\": \"USD Coin\",\n        \"decimals\": 6,\n        \"balanceRaw\": \"1000000\",\n        \"balance\": \"1.0\",\n        \"priceUSD\": 1,\n        \"balanceUSD\": 1\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParseTokenBalancesRequest"
              },
              "example": {
                "rpcCallId": "string",
                "rawResponses": [
                  "string"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token balances with USD values",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenBalancesResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "chainId": "1",
                    "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5",
                    "count": 1,
                    "items": [
                      {
                        "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                        "symbol": "USDC",
                        "name": "USD Coin",
                        "decimals": 6,
                        "balanceRaw": "1000000",
                        "balance": "1.0",
                        "priceUSD": 1,
                        "balanceUSD": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "404": {
            "description": "RPC call context not found or expired (older than 5 minutes). Call `/token/balances/rpc-call` again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "parse-token-balances"
      }
    },
    "/v1/data/token/available": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Get available lending assets",
        "description": "Returns the list of assets available for lending on a given chain. Proxied from origin with a long-lived cache (1 hour).\n\n**Filters:**\n- `chainId` / `chainIds` — filter by chain\n- `lender` — filter by lender protocol\n- `symbol`, `name`, `address` — filter by asset metadata\n- `assetGroup` — filter by asset group\n\n**Response Structure:**\n- `count`: Number of matching assets\n- `items`: Array of asset objects with address, chain_id, symbol, name, and additional metadata\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/available`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. |\n| `chainIds` | query | string | no | Comma-separated chain IDs to filter by (alternative to chainId) See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | no | Filter by lender protocol key See the `LenderId` schema for the full set of accepted values. |\n| `symbol` | query | string | no | Filter by token symbol |\n| `name` | query | string | no | Filter by token name (partial match) |\n| `address` | query | string | no | Filter by token contract address |\n| `assetGroup` | query | string | no | Filter by asset group |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.count` | integer | Number of available assets |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].address` | string | Token contract address |\n| `data.items[].chain_id` | integer | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.items[].symbol` | string | Token symbol, e.g. `WETH`. |\n| `data.items[].name` | string | Human-readable display name. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 1,\n    \"items\": [\n      {\n        \"address\": \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n        \"chain_id\": 1,\n        \"symbol\": \"USDC\",\n        \"name\": \"USD Coin\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Filter by chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "chainIds",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1,42161"
            },
            "description": "Comma-separated chain IDs to filter by (alternative to chainId) See the `ChainId` schema for the full set of supported chains.",
            "example": "1,42161"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Filter by lender protocol key See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "symbol",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC"
            },
            "description": "Filter by token symbol",
            "example": "USDC"
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USD Coin"
            },
            "description": "Filter by token name (partial match)",
            "example": "USD Coin"
          },
          {
            "name": "address",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
            },
            "description": "Filter by token contract address",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
          },
          {
            "name": "assetGroup",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "USDC"
            },
            "description": "Filter by asset group",
            "example": "USDC"
          }
        ],
        "responses": {
          "200": {
            "description": "Available lending assets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenAvailableResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 1,
                    "items": [
                      {
                        "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                        "chain_id": 1,
                        "symbol": "USDC",
                        "name": "USD Coin"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "get-available-lending-assets"
      }
    },
    "/v1/data/token/balances/lending": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Lending token balances",
        "description": "Fetches token balances for all available lending assets on a chain for a given account. Combines the available-assets lookup with balance fetching in a single call.\n\n**How it works:**\n1. Fetches all available lending asset addresses from origin (optionally filtered by lender)\n2. Fetches token balances for those assets via multicall\n3. Enriches with token metadata, prices, and USD values\n\n**Response Structure:**\n- `items`: Array of non-zero balance entries (same format as `/token/balances`)\n- `count`: Number of tokens with non-zero balance\n\n**Balance Entry includes:**\n- `address`: Token contract address (zeroAddress for native)\n- `symbol`: Token symbol\n- `name`: Token name\n- `decimals`: Token decimals\n- `balanceRaw`: Raw balance as string (wei/smallest unit)\n- `balance`: Formatted balance as decimal string\n- `priceUSD`: Per-unit USD price\n- `balanceUSD`: Balance value in USD\n\n**Note:** Zero-balance entries are excluded. The native token balance is included only if non-zero.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/balances/lending`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) |\n| `lender` | query | string | no | Optional lender filter — only fetch assets available on this protocol See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.account` | string | Lowercase account address |\n| `data.count` | integer | Number of balance entries |\n| `data.items` | object[] | The result set for this response. |\n| `data.items[].address` | string | Token contract address (zeroAddress for native) |\n| `data.items[].symbol` | string | Token symbol, e.g. `WETH`. |\n| `data.items[].name` | string | Human-readable display name. |\n| `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. |\n| `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) |\n| `data.items[].balance` | string | Formatted balance as decimal string |\n| `data.items[].priceUSD` | number | Per-unit USD price of the token |\n| `data.items[].balanceUSD` | number | Balance value in USD |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainId\": \"1\",\n    \"account\": \"0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5\",\n    \"count\": 1,\n    \"items\": [\n      {\n        \"address\": \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\n        \"symbol\": \"USDC\",\n        \"name\": \"USD Coin\",\n        \"decimals\": 6,\n        \"balanceRaw\": \"1000000\",\n        \"balance\": \"1.0\",\n        \"priceUSD\": 1,\n        \"balanceUSD\": 1\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
            },
            "description": "EVM account address (0x-prefixed, 40 hex chars)",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          {
            "name": "lender",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Optional lender filter — only fetch assets available on this protocol See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          }
        ],
        "responses": {
          "200": {
            "description": "Token balances for all lending assets with USD values",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenBalancesResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "chainId": "1",
                    "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5",
                    "count": 1,
                    "items": [
                      {
                        "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                        "symbol": "USDC",
                        "name": "USD Coin",
                        "decimals": 6,
                        "balanceRaw": "1000000",
                        "balance": "1.0",
                        "priceUSD": 1,
                        "balanceUSD": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "lending-token-balances"
      }
    },
    "/v1/data/token/prices": {
      "get": {
        "tags": [
          "Token"
        ],
        "summary": "Token prices by address",
        "description": "Returns per-address USD prices for the given asset addresses on a chain.\n\n**How it works:**\n1. Resolves each address to its asset group via the token list\n2. Looks up the latest USD price for each asset group\n3. Returns a map of address → price\n\n**Query format:**\n- `assets`: Comma-separated list of EVM addresses (0x-prefixed, 40 hex chars)\n\n**Response Structure:**\n- `items`: Object mapping lowercase addresses to their USD price (0 if unknown)\n- `count`: Number of resolved assets\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/token/prices`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `assets` | query | string | yes | Comma-separated list of token addresses |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.count` | integer | Number of resolved assets |\n| `data.items` | object | Map of lowercase address → USD price |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"chainId\": \"1\",\n    \"count\": 1,\n    \"items\": {\n      \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\": 1,\n      \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\": 3500.12\n    }\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "assets",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Comma-separated list of token addresses",
            "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-address USD prices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/TokenPricesResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "chainId": "1",
                    "count": 1,
                    "items": {
                      "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": 1,
                      "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": 3500.12
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "token-prices-by-address"
      }
    },
    "/v1/data/vaults": {
      "get": {
        "tags": [
          "Vaults (Data)"
        ],
        "summary": "Get vault data across providers",
        "operationId": "vaults",
        "description": "Returns public vault data across the supported ERC-4626-style providers on a single chain. By default this is served from the recorder origin — a DB-backed, USD-priced, **paginated** listing — and the response is a flat `{ start, count, items[] }` envelope (one entry per vault, see *Response shape* below).\n\n**Pagination** — `start` is the row offset and `limit` the page size; the origin returns up to one page per call. To walk a chain, request `start=0`, then `start=limit`, `start=2*limit`, … until fewer than `limit` items come back. This is intentional: large chains return hundreds of vaults and are paged rather than returned in one payload.\n\n**Legacy live mode** — pass `source=live` to bypass the origin and compute the data live on-chain via multicall. This returns the older **provider-keyed** `VaultPublicDataAll` shape (one key per provider, *not* `items[]`) and ignores `start`/`limit`. It is also the automatic fallback when no origin is configured (e.g. local dev) or the origin is unreachable.\n\n**Supported providers**\n\n| key | source |\n|---|---|\n| `fluid` | Fluid `fTokens` (ERC-4626 yield tokens) and vaults (NFT-position margin markets) |\n| `gearbox` | Gearbox V3 passive PoolV3 (ERC-4626 Diesel shares) |\n| `morpho` | Morpho Blue MetaMorpho vaults |\n| `lista` | Lista DAO earn vaults (Moolah-fork of MetaMorpho, BNB chain; fetched on-chain) |\n| `silo` | Silo V2 + V3 isolated lending vaults (GraphQL-backed) |\n| `euler-earn` | Euler V2 Earn vaults (ERC-4626) |\n| `lst` | Protocol-issued liquid-staking share tokens (Lido wstETH, Rocket Pool rETH, EtherFi weETH, Renzo ezETH, Kelp rsETH, Swell rswETH/swETH, Puffer pufETH, YieldNest ynETH, StakeWise osETH, Stader ETHx, Mantle mETH, Coinbase cbETH). Ethereum only in this drop. |\n| `savings` | ERC-4626 yield-bearing-stablecoin wrappers (Ethena sUSDe, Sky sUSDS/stUSDS, Maker sDAI, Reservoir wsrUSD, YieldFi yUSD, Resolv wstUSR, Angle stUSD/stEUR, Falcon sUSDf, InfiniFi siUSD, Maple syrupUSDC/syrupUSDT). Plus Avant savUSD on Avalanche and YO yoETH on Base. |\n| `yearn` | Yearn V3 vaults (VaultV3 + TokenizedStrategy ERC-4626) on Ethereum, Polygon, Base, Arbitrum, Gnosis, Sonic, Katana. Discovered + priced via the yDaemon API. |\n| `aave-earn` | Aave Earn (\"stable\") vaults — curator-run ERC-4626 wrappers over an Aave v3 supply position. Discovered + priced via the Aave public GraphQL API (`api.v3.aave.com`) by tracked curator/vault, enriched on-chain for `totalSupply` + share price. |\n\n**Response shape**\n\n*Default (origin) mode:* `{ start, count, items[] }` where each item is a normalized, USD-priced vault record: `{ chainId, provider, vaultAddress, underlying, symbol, name, displayName, curatorName, decimals, assetDecimals, dataTs, updatedAt, rates: { depositRate, rewardsRate, totalRate, fee }, tvl: { totalAssets, totalSupply, totalAssetsFormatted, totalAssetsUsd }, liquidity: { liquidity, liquidityFormatted, liquidityUsd }, underlyingInfo, vaultInfo, curatorEntity, providerMeta, … }`. `totalAssetsUsd` / `liquidityUsd` are computed by the recorder from its own price store (see margin-fetcher `DATABASE_INTEGRATION.md`).\n\nThree metadata bundles travel with every item (mirroring lending's `underlyingInfo` + `lenderInfo`):\n\n- **`underlyingInfo`** — the underlying token: `{ asset: { chainId, address, symbol, name, decimals, logoURI, assetGroup, currencyId, props }, prices: { priceUsd, priceTs } }`.\n- **`vaultInfo`** — the vault's *own* identity: `{ address, symbol, name, logoURI, assetGroup, yieldProfile, denomination }`. `logoURI` is resolved from the **share token's** token-list entry, falling back to the underlying asset's logo. `name` uses the branded share-token name for `lst`/`savings` (e.g. *etherFi weETH*) and the curated label elsewhere (e.g. *Steakhouse USDC*).\n- **`curatorEntity`** — the curator's `{ name, logoUri }` from the curator registry, or `null`.\n\n*Legacy live mode (`source=live`):* the top-level object is keyed by provider name. Each provider's value is a free-form payload from `@1delta/margin-fetcher`'s `getVaultPublicDataAll` — schemas diverge per provider (see the package's types for exact field shapes). Common fields across most providers: vault/share token address, underlying asset, supply rate, total assets / supply, and provider-specific metadata (e.g. Fluid `vaultId`, Silo `siloAddress`).\n\n**LST deposit metadata (`providerMeta` on `lst` items)**\n\n`lst` records carry the data needed to build a deposit without reading SDK source:\n\n- `isMintable` — `false` ⇒ no permissionless on-chain mint (e.g. cbETH); skip the action endpoint.\n- `mintContract` — the mint target.\n- `exchangeRate` / `convertToShares` — to compute expected output and a `minOut`.\n- `isRebasing` — output-balance semantics (stETH/eETH rebase; wstETH/weETH don't).\n- `mintInputAsset` — the **primary** pay asset (`native` or an ERC-20 address).\n- **`acceptedInputs[]`** — the full accept-set, each `{ asset: \"native\"|\"0x…\", symbol?, mode: \"direct\"|\"wrap\"|\"submit-wrap\", needs?: string[] }`. `asset` is what to pass as `payAsset`; `needs` lists the option query params that path requires. This is the machine-readable answer to \"what can I pay with\"; drive the deposit request off it. See `GET /v1/actions/vaults/lst` for the build flow.\n- **`delegation`** — present only when the deposit requires/allows picking a validator/group/node/pool: `{ required, kind, optionKey, default, source }`. **Absent ⇒ pooled** (no picker needed). When present and `source: \"endpoint\"`, fetch the selectable set from [/v1/data/vaults/validators](/1delta-api/vaults-validators) and send the chosen `id` back to the deposit as the param named by `delegation.optionKey`. This is the flag that tells the UI whether a validator fetch is needed. Attached by the worker in both origin and `source=live` modes.\n\n**Exit fees (`withdrawFeeBps`)**\n\nBasis points (`10` = 0.10 %), on `gearbox` pools and on `savings` entries whose `withdrawalMode` is `fee-or-queued` (Native Credit Pool `wNLP`). Distinct from `rates.fee`, which is a **performance** fee skimmed from yield — `withdrawFeeBps` is a one-off charge on the way **out**.\n\nFor Native `wNLP` specifically, an exit has two legs and only one of them is priced by this field:\n\n- **Instant** (`instantRedeem`) — the fee is deducted from the underlying paid to the receiver, never collected as a separate transfer, so the caller neither funds nor approves it: `received = shares × exchangeRate × (1 − withdrawFeeBps/10_000)`. Capped by `liquidity`, which is a **gross** figure — what actually lands is `liquidity × (1 − withdrawFeeBps/10_000)`.\n- **Queued** (`requestWithdrawal` → wait `withdrawalCooldownSeconds` → `claim`) — pays at par, so `withdrawFeeBps` does not apply. Its cost is implicit: the payout is snapshotted at request time and yield accruing over the wait goes to the protocol. At a 3-day window that is worth a few bps against a 100 bps instant fee, which is why the action builders default to the queue and require `instant=true` to take the haircut.\n\nThere is no deposit or management fee on these vaults — `exchangeRate` and the reported rates are already net. `instantRedeemEnabled: false` means the pool is queue-only and `withdrawFeeBps` is unreachable.\n\n**Lockup likelihood (`instantLiquidityRatio`, `savings` items)**\n\n`liquidity / totalAssets` clamped to `0…1` — the share of the vault exitable **this block**, so `1 − instantLiquidityRatio` is the share that must queue. `instant` vaults report `1`, cooldown/queued/request-based report `0`, and Native `fee-or-queued` pools report live coverage (observed across the full range: `1.00` on Ethereum `wNLP-USDC`, `0.20` on `wNLP-WBTC`, `0.0005` on BNB `wNLP-T4B`).\n\nNot named `utilization` on purpose: these protocols expose no debt accumulator, so `borrowed / supplied` is not readable per pool — this measures exit **coverage** instead, which is what actually predicts lockup. Two caveats: Native's buffer also custodies market-maker collateral so it can exceed the pool it serves (hence the clamp — `1` means \"fully covered\", not \"zero utilization\"), and it is a live spot reading that moves as market makers draw inventory. Nothing is lost below `1`; the remainder redeems at par through the queue.\n\n**Related action endpoints**\n\n- `GET /v1/actions/vaults/deposit` — ERC-4626 deposit via the 1delta Composer, with optional Fluid native-deposit path. Also serves Native `wNLP` (auto-detected; no `underlying` needed).\n- `GET /v1/actions/vaults/withdraw` — ERC-4626 withdraw via the 1delta Composer, with native-unwrap support. Also serves Native `wNLP` (`instant=true` for the fee-paying leg).\n- `GET /v1/actions/vaults/lst` — LST/LRT mint · withdraw-request · claim · cancel, driven by the `acceptedInputs` above.\n- `GET /v1/actions/vaults/savings` — cooldown/queued savings exits, plus Native `wNLP` deposit · request-withdraw · claim · cancel.\n\nFor Fluid **margin vaults** (the NFT-position kind, not fTokens), the lending action endpoints (`/v1/actions/lending/{deposit,withdraw,borrow,repay}`) are the right surface — they understand the per-vault `FLUID_<chainId>_<vaultId>` lender keys and Fluid's NFT ownership model (including the pre-flight `ownerOf` validation for deposit-to-existing-NFT with a custom `receiver`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/vaults`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID to query See the `ChainId` schema for the full set of supported chains. |\n| `start` | query | integer | no | Pagination offset (origin mode). Row index of the first item to return. Non-negative integer; defaults to 0. |\n| `limit` | query | integer | no | Pagination page size (origin mode). Max items to return per call. Non-negative integer. Ignored in `source=live` mode. |\n| `provider` | query | string | no | Origin mode: narrow the listing to a single provider (e.g. `morpho`). |\n| `source` | query | `live` | no | Set to `live` to bypass the origin and compute on-chain via multicall (returns the legacy provider-keyed shape; `start`/`limit` ignored). |\n| `providers` | query | string | no | Legacy live mode only (`source=live`): CSV of vault providers to include. Defaults to all (`fluid,gearbox,morpho,lista,silo,euler-earn,lst,savings,lagoon,aave-earn,upshift,yearn,hypercore,gmx`). Unknown providers return 400. |\n| `siloProtocolVersion` | query | `v2`, `v3` | no | Narrow the Silo query to a single protocol version. Has no effect on other providers. |\n| `siloLimit` | query | integer | no | Page-size hint for the Silo GraphQL query (positive integer). |\n| `terms` | query | `digest`, `full`, `none` | no | Term-sheet depth attached to every vault as `termSheet` — the SAME shape and the same parameter as `/v1/data/lending/latest`, so one renderer handles an Aave reserve and a Pendle PT. A vault carries `termSheet.supply` only; `borrow` is absent, and that absence is the statement that it cannot be borrowed. `digest` (default) is the compact form; `full` inlines `info.description`, `backedBy.items[]` and the `coverage` map; `none` omits the field. **Read `coverage` before trusting a silence** — it separates \"does not apply here\" (`notApplicable`) from \"not wired yet\" (`pending`), so an absent `governance` block never reads as \"ungoverned\". Origin mode only. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID to query See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 0
            },
            "description": "Pagination offset (origin mode). Row index of the first item to return. Non-negative integer; defaults to 0.",
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 100
            },
            "description": "Pagination page size (origin mode). Max items to return per call. Non-negative integer. Ignored in `source=live` mode.",
            "example": 100
          },
          {
            "name": "provider",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "morpho"
            },
            "description": "Origin mode: narrow the listing to a single provider (e.g. `morpho`).",
            "example": "morpho"
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "live"
              ]
            },
            "description": "Set to `live` to bypass the origin and compute on-chain via multicall (returns the legacy provider-keyed shape; `start`/`limit` ignored)."
          },
          {
            "name": "providers",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "fluid,morpho"
            },
            "description": "Legacy live mode only (`source=live`): CSV of vault providers to include. Defaults to all (`fluid,gearbox,morpho,lista,silo,euler-earn,lst,savings,lagoon,aave-earn,upshift,yearn,hypercore,gmx`). Unknown providers return 400.",
            "example": "fluid,morpho"
          },
          {
            "name": "siloProtocolVersion",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "v2",
                "v3"
              ]
            },
            "description": "Narrow the Silo query to a single protocol version. Has no effect on other providers."
          },
          {
            "name": "siloLimit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Page-size hint for the Silo GraphQL query (positive integer)."
          },
          {
            "name": "terms",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "digest",
                "full",
                "none"
              ],
              "default": "digest",
              "example": "full"
            },
            "description": "Term-sheet depth attached to every vault as `termSheet` — the SAME shape and the same parameter as `/v1/data/lending/latest`, so one renderer handles an Aave reserve and a Pendle PT. A vault carries `termSheet.supply` only; `borrow` is absent, and that absence is the statement that it cannot be borrowed. `digest` (default) is the compact form; `full` inlines `info.description`, `backedBy.items[]` and the `coverage` map; `none` omits the field. **Read `coverage` before trusting a silence** — it separates \"does not apply here\" (`notApplicable`) from \"not wired yet\" (`pending`), so an absent `governance` block never reads as \"ungoverned\". Origin mode only.",
            "example": "full"
          }
        ],
        "responses": {
          "200": {
            "description": "Origin mode: `{ start, count, items[] }` paginated, USD-priced vault records. Legacy live mode (`source=live`): provider-keyed vault data, with failed providers omitted (the worker logs a warning but does not propagate per-provider errors).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/vaults/user": {
      "get": {
        "tags": [
          "Vaults (Data)"
        ],
        "summary": "Get user balances across ERC-4626 vaults",
        "operationId": "vaults-user",
        "description": "Returns per-vault balances for `account` across the supplied ERC-4626 share-token addresses. Static vault metadata (underlying, decimals, share-price ratio) is sourced from the cached `/v1/data/vaults` public-data fetch, so this endpoint's only on-chain footprint is exactly one `balanceOf(account)` per vault.\n\n**Why this exists**\n\nVault shares are plain ERC-20s, so `/v1/data/token/balances` can read them — but it can't convert shares → assets. This endpoint folds that conversion in so the frontend doesn't have to redo `shares * totalAssets / totalSupply` math (and get the rounding subtly wrong).\n\n**Scope**\n\nVault addresses must be tracked by `/v1/data/vaults` (the 5 supported providers — `fluid`, `gearbox`, `morpho`, `silo`, `euler-earn`). Unknown addresses are listed back to the caller in the response's `unknown` field; a request that contains *only* unknown addresses returns 400. Untracked vaults are intentionally not auto-included — the 1delta data layer only surfaces vaults that have passed risk review.\n\n**Per-item fields** (naming mirrors `/v1/data/token/balances` — `<thing>Raw` is a stringified uint, `<thing>` is the formatted human-readable string)\n\n| field | meaning |\n|---|---|\n| `vault` | share-token address (echoes the input) |\n| `underlying` | result of `vault.asset()` |\n| `symbol`, `name`, `decimals` | from the token registry / on-chain `decimals()` |\n| `sharesRaw` / `shares` | raw uint + formatted balance in vault tokens |\n| `assetsRaw` / `assets` | shares converted to underlying at the current fair share price (via `convertToAssets`) — raw uint + formatted |\n| `priceUSD` | unit price of the underlying |\n| `balanceUSD` | `assets * priceUSD` — USD value of the position |\n\n**Resilience**\n\nFailed reads (e.g. a non-ERC-4626 address slipped into the list, or a vault that reverts on `convertToAssets`) are silently dropped from the response — the whole request is not failed. Vaults the user hasn't deposited into (zero shares) are kept in the response so the caller can render a deterministic table.\n\n**Scope**\n\nThis is for passive ERC-4626 vaults (Fluid fTokens, MetaMorpho, Gearbox V3 pools, Silo, Euler Earn). For Fluid's NFT-position **margin vaults**, use `/v1/data/lending/user-positions` instead — it understands the `FLUID_<chainId>_<vaultId>` lender keys and the NFT-per-position model.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/vaults/user`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | User address (EOA or contract) |\n| `vaults` | query | string | yes | CSV of ERC-4626 share-token addresses to query. Duplicates are de-duped; invalid addresses are skipped. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "User address (EOA or contract)",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "vaults",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8,0xBEEF01735c132Ada46AA9aA4c54623caA92A64CB"
            },
            "description": "CSV of ERC-4626 share-token addresses to query. Duplicates are de-duped; invalid addresses are skipped.",
            "example": "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8,0xBEEF01735c132Ada46AA9aA4c54623caA92A64CB"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-vault balances joined with underlying prices. Items with failed reads are omitted; zero-share entries are kept.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/vaults/validators": {
      "get": {
        "tags": [
          "Vaults (Data)"
        ],
        "summary": "Get selectable validators for an LST deposit",
        "operationId": "vaults-validators",
        "description": "Returns the selectable **delegation targets** (validators / validator-groups / nodes) for an LST that lets — or requires — the depositor to choose where the stake is delegated. The companion to the `delegation` descriptor carried on each `lst` item in [/v1/data/vaults](/1delta-api/vaults): the descriptor says *whether* a choice is needed and the deposit option key to send it back as; this endpoint returns the live set.\n\n**The flow**\n\n1. `/v1/data/vaults?provider=lst` → an item's `providerMeta.delegation` tells you if a choice is needed:\n   - **absent** ⇒ pooled LST (Lido, Rocket Pool, …) — no picker, deposit directly.\n   - `{ required, kind, optionKey, default, source }` ⇒ a selection applies.\n2. If `source: \"endpoint\"`, call this endpoint to populate the picker.\n3. Send the chosen item's `id` back to /v1/actions/vaults/deposit as the param named by `delegation.optionKey` (e.g. `validator=<id>` for Core, `validatorGroup=<id>` for Celo).\n\n**Behaviour by LST type**\n\n- **Required** (Core stCORE — `validator`): the picker is mandatory; preselect the `recommended` item.\n- **Optional / auto** (Celo stCELO — `validatorGroup`, `default: \"auto\"`): the picker is optional — omit the choice and the deposit endpoint auto-resolves a valid group. Offer it as an \"advanced\" control.\n- **Off-chain** (Solv — `poolId`, `source: \"offchain\"`): `items[]` is empty — the value comes from the protocol's docs, not the chain. Render an input, not a list.\n- **Pooled / unknown**: `delegation: null`, empty `items[]` (200, not 404) so a UI can treat \"no selection\" uniformly.\n\n**Per-item fields**\n\n| field | meaning |\n|---|---|\n| `id` | the opaque value to pass back as `delegation.optionKey` (validator / group / node address) |\n| `status` | `active` · `inactive` · `jailed` · `full` — only `active` targets are `selectable` |\n| `selectable` | passes the protocol's eligibility (healthy + not blocked + has room) |\n| `recommended` | the default pick (best capacity / health) — preselect this |\n| `receivableVotes` | remaining capacity (raw underlying string), where the protocol exposes it (Celo) — show as \"room left\" so a user avoids a near-full target |\n\nOnly the selectable set is returned today; per-validator APR / commission are populated as clean sources are wired (absent ⇒ not yet available, never approximated).\n\nResults are cached ~60s (validator metadata moves per epoch/round, not per block).\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/vaults/validators`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `shareToken` | query | string | yes | LST share-token address (alias: `vault`). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "42220"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "42220"
          },
          {
            "name": "shareToken",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xc668583dcbdc9ae6fa3ce46462758188adfdfc24"
            },
            "description": "LST share-token address (alias: `vault`).",
            "example": "0xc668583dcbdc9ae6fa3ce46462758188adfdfc24"
          }
        ],
        "responses": {
          "200": {
            "description": "`{ chainId, shareToken, delegation, start, count, items[] }`. `delegation` is null for pooled/unknown share tokens; `items[]` is empty for pooled or off-chain (Solv poolId) selections.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/data/vaults/withdrawals": {
      "get": {
        "tags": [
          "Vaults (Data)"
        ],
        "summary": "Get a user's pending vault withdrawal requests",
        "operationId": "vaults-withdrawals",
        "description": "Returns a user's **pending withdrawal requests** across every vault that has a withdrawal queue / cooldown (LSTs, savings cooldowns, ERC-7540 async vaults). The static LST/savings withdrawal registry is always probed; pass `vaults` to additionally read arbitrary ERC-7540 vaults by address.\n\nEach entry is normalised to a uniform shape so the frontend treats every protocol identically — render the list, and when `status === \"claimable\"` build the claim via the matching action endpoint ([/v1/actions/vaults/lst](/1delta-api/vaults-lst) or [/savings](/1delta-api/vaults-savings)).\n\n**Response:** `{ chainId, account, count, requests }`, where each `requests[]` entry carries:\n\n| field | meaning |\n|---|---|\n| `lst` | the share-token the request was made against |\n| `brand`, `symbol` | UI labels |\n| `requestId` | protocol-native id (NFT tokenId, queue index, 7540 requestId, or a bucket name like `waiting`/`unbonded`) — pass back to the claim action |\n| `amountUnderlying` | wei the request returns on claim (expected amount for floating-rate queues) |\n| `status` | `pending` · `claimable` · `claimed` · `expired` |\n| `readyAt` | unix seconds the request becomes claimable (fixed-cooldown protocols only) |\n| `yieldProfile`, `denomination` | present when the vault is in the public-data lookup |\n\nEmpty per-vault results are dropped.\n\n<details>\n<summary>Plain-text reference — `GET /v1/data/vaults/withdrawals`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | 0x-prefixed holder address. |\n| `vaults` | query | string | no | Optional CSV of extra ERC-7540 vault addresses to probe with the generic async-redeem reader, in addition to the static registry. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "0x-prefixed holder address.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "vaults",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional CSV of extra ERC-7540 vault addresses to probe with the generic async-redeem reader, in addition to the static registry."
          }
        ],
        "responses": {
          "200": {
            "description": "Flat `requests[]` of pending withdrawal requests across all queued/cooldown vaults for `account`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions": {
      "get": {
        "tags": [
          "Index"
        ],
        "summary": "List action endpoints",
        "description": "Returns a flat directory of every action endpoint, grouped by category (`lending`, `loop`, `swap`, `allocate`). Useful for client-side discovery and link generation.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions`</summary>\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational payload. `null` when the endpoint only builds calldata. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {}\n}\n```\n\n</details>\n",
        "responses": {
          "200": {
            "description": "Endpoint listing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Informational payload. `null` when the endpoint only builds calldata."
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {}
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "list-action-endpoints"
      }
    },
    "/v1/actions/lending/deposit": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Deposit",
        "operationId": "lending-deposit",
        "description": "Build calldata for depositing into a lending pool. Use `mode=direct` (default) for raw protocol interaction or `mode=proxy` for 1delta composer. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics.\n\n**Morpho Midnight order-book markets (`MORPHO_MIDNIGHT_<id>`):** depositing = **lending** = **TAKING** the ask side of the book — this endpoint fills the `lendOffers` returned by [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest), best-first. To post your own limit offer instead (MAKE), use [`/v1/actions/midnight/make`](/1delta-api/midnight-make).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/deposit`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `payAsset` | query | string | no | Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata and approvals for deposit",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxyResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Deposit (simulate)",
        "description": "Build calldata for depositing into a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/lending/deposit`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `payAsset` | query | string | no | Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Simulation results including projected health factor and borrow capacity |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction calldata with post-trade simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawSimulationResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxySimulationResponse"
                        }
                      ],
                      "description": "Simulation results including projected health factor and borrow capacity"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "deposit-simulate"
      }
    },
    "/v1/actions/lending/simulate": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Simulate a base lending operation on-chain",
        "operationId": "lending-simulate",
        "description": "Build a base lending operation and **execute it against live chain state** before the user signs it.\n\nThis is an EVM check, not the arithmetic projection that `simulate=true` adds to the other lending endpoints. The transaction is built by the very endpoint the client would call (`/v1/actions/lending/{action}`) and then replayed through an `eth_call` with storage overrides — so what is verified is the exact calldata that would be submitted, including the lender quirks that only surface on-chain.\n\n**Scope is the four single-grant operations.** `deposit` and `repay` override the pay token (funding balance and approval in one write); `withdraw` and `borrow` override the lender's own grant mapping (Aave credit delegation, Morpho `isAuthorized`, Comet `isAllowed`) so the action can be previewed *before* the user has signed that permission. Anything needing two grants at once — notably a leverage open that pulls fresh margin **and** borrows on behalf — cannot be previewed cold and is out of scope.\n\n**The override is optimistic.** `willSucceed: true` with `grantOverridden: true` means \"this succeeds once the permission exists\"; it is not evidence the permission exists. Keep gating the real grant on the permissions array.\n\nThe `simulation` object is either:\n- `{ simulated: true, willSucceed, gasUsed, amountOut, returnData, revertReason?, block, grantOverridden }`\n- `{ simulated: false, reason, detail }` — where `reason` is one of `NO_TRANSACTION`, `MULTI_STEP`, `NATIVE_VALUE`, `MULTIPLE_GRANTS`, `GRANT_SLOT_UNKNOWN`, `SIMULATOR_UNAVAILABLE`.\n\nNote `amountOut` is a measured balance delta on `operator`, so it reads `0` for lenders with no receipt token (Morpho Blue and every CDP-shaped lender) — those return their own values in `returnData` instead. A simulator outage never fails the request: the calldata is still returned and remains valid.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/simulate`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `action` | query | string | yes | Which base operation to build and replay: `deposit`, `withdraw`, `borrow` or `repay`. |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `payAsset` | query | string | no | Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n| `block` | query | string | no | Block number or tag to simulate against. Defaults to `latest`. |\n\n</details>\n",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Which base operation to build and replay: `deposit`, `withdraw`, `borrow` or `repay`."
          },
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          },
          {
            "name": "block",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Block number or tag to simulate against. Defaults to `latest`."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata plus the on-chain execution result"
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/lending/withdraw": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Withdraw",
        "operationId": "lending-withdraw",
        "description": "Build calldata for withdrawing from a lending pool. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. When on-chain deposit data is available and `amount` covers the full deposit balance, the API uses protocol-level max-withdraw mechanisms automatically (e.g. `maxUint256` or share-based redemption). If `isAll=true` but `amount` is less than the deposit balance, the API falls back to a partial withdrawal to avoid reverts.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/withdraw`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `isAll` | query | boolean | no | Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is. |\n| `receiveAsset` | query | string | no | Asset to receive.\n\nUse the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is."
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to receive.\n\nUse the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata and approvals for withdraw",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxyResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Withdraw (simulate)",
        "description": "Build calldata for withdrawing from a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/lending/withdraw`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `isAll` | query | boolean | no | Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is. |\n| `receiveAsset` | query | string | no | Asset to receive.\n\nUse the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Simulation results including projected health factor and borrow capacity |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is."
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to receive.\n\nUse the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction calldata with post-trade simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawSimulationResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxySimulationResponse"
                        }
                      ],
                      "description": "Simulation results including projected health factor and borrow capacity"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "withdraw-simulate"
      }
    },
    "/v1/actions/lending/borrow": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Borrow",
        "operationId": "lending-borrow",
        "description": "Build calldata for borrowing from a lending pool. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics.\n\n**Lista DAO fixed-term (brokered) markets:** when the market is brokered (its public data has a non-empty `terms[]` rate card and `flags.variableBorrowDisabled === true`), pass `termId` to open a fixed-rate, fixed-term loan at the chosen term. Omitting `termId` on a brokered market opens the flexible (variable) position — direct mode only, since the broker has no on-behalf flex-borrow overload for the composer path.\n\n**Morpho Midnight order-book markets (`MORPHO_MIDNIGHT_<id>`):** borrowing = **TAKING** the bid side of the book — this endpoint fills the `offers` returned by [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest), best-first. Borrowing is fixed-rate / fixed-maturity but has no `termId` (a single calendar maturity per market). To post your own limit offer instead (MAKE), use [`/v1/actions/midnight/make`](/1delta-api/midnight-make).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/borrow`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `termId` | query | integer | no | **Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the\nmarket's `terms[]` rate card (the `termId` of the chosen entry).\n\nA market is brokered when its public data carries a non-empty `terms[]` array and\n`flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the\ndebt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it\nis omitted on a brokered market the borrow falls back to the flexible (variable) position\n(direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term).\n\nIgnored for non-brokered lenders. |\n| `receiveAsset` | query | string | no | Asset to receive.\n\nUse the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults).\n\nProxy mode: defaults to market asset. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "lendingMode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "termId",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 2
            },
            "description": "**Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the\nmarket's `terms[]` rate card (the `termId` of the chosen entry).\n\nA market is brokered when its public data carries a non-empty `terms[]` array and\n`flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the\ndebt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it\nis omitted on a brokered market the borrow falls back to the flexible (variable) position\n(direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term).\n\nIgnored for non-brokered lenders.",
            "example": 2
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to receive.\n\nUse the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults).\n\nProxy mode: defaults to market asset."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata and approvals for borrow",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxyResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Borrow (simulate)",
        "description": "Build calldata for borrowing from a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/lending/borrow`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `termId` | query | integer | no | **Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the\nmarket's `terms[]` rate card (the `termId` of the chosen entry).\n\nA market is brokered when its public data carries a non-empty `terms[]` array and\n`flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the\ndebt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it\nis omitted on a brokered market the borrow falls back to the flexible (variable) position\n(direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term).\n\nIgnored for non-brokered lenders. |\n| `receiveAsset` | query | string | no | Asset to receive.\n\nUse the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults).\n\nProxy mode: defaults to market asset. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Simulation results including projected health factor and borrow capacity |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "lendingMode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "termId",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 2
            },
            "description": "**Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the\nmarket's `terms[]` rate card (the `termId` of the chosen entry).\n\nA market is brokered when its public data carries a non-empty `terms[]` array and\n`flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the\ndebt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it\nis omitted on a brokered market the borrow falls back to the flexible (variable) position\n(direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term).\n\nIgnored for non-brokered lenders.",
            "example": 2
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to receive.\n\nUse the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults).\n\nProxy mode: defaults to market asset."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction calldata with post-trade simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawSimulationResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxySimulationResponse"
                        }
                      ],
                      "description": "Simulation results including projected health factor and borrow capacity"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "borrow-simulate"
      }
    },
    "/v1/actions/lending/repay": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Repay",
        "operationId": "lending-repay",
        "description": "Build calldata for repaying a loan. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. When on-chain debt data is available and `amount` covers the full debt, the API uses protocol-level max-repay mechanisms automatically. If `isAll=true` but `amount` is less than the debt, the API falls back to a partial repay to avoid reverts.\n\n**Lista DAO fixed-term (brokered) markets:** pass `loanId` to target a specific loan (use the per-loan `loanId` from the user-positions response, or the `type(uint128).max` sentinel for the flexible/dynamic position). The broker repays interest-first plus an early-repayment penalty on not-yet-matured fixed loans and refunds any excess, so to fully close a loan fund `outstanding + accruedInterest + earlyRepayPenalty` from the per-loan `term`.\n\n**Morpho Midnight fixed-term markets (`MORPHO_MIDNIGHT_<id>`) — repaying to avoid liquidation.** A Midnight loan is **zero-coupon and fixed-maturity**: you owe a *static face value* — the position's `debt` in loan-token units — repaid **1:1**, which does **not** grow over time. So the amount to repay is fixed and known up front (the continuous + settlement fees accrue on the *lender's* side and are **never** added to your debt), and there is **no early-repayment penalty** (unlike Lista) — you may repay any time before maturity at face value.\n\nA borrower faces **two** liquidation triggers; both are cleared by repaying:\n\n- **Before maturity — health (LTV) based.** As with any collateralised loan, if the collateral's oracle value falls enough to breach the market's LLTV, the position can be liquidated. Keep an LTV buffer, add collateral, or repay down.\n- **At/after maturity — default.** The fixed `maturity` (surfaced on `params.market.maturity`) is a **hard deadline**. Once it passes, an unrepaid loan is **in default and can be liquidated regardless of health or LTV** — being past-due is itself the trigger. This is the Midnight-specific risk to watch: mark the maturity date and fully repay **before** it, even if the position is comfortably collateralised.\n\n**Repay exactly the debt.** Over-repaying **reverts** on-chain (there is no over-repay buffer — do **not** pad the `amount`, and `isAll` does not auto-size here), while under-repaying leaves a dust position that stays open and therefore still liquidatable after maturity. Set `amount` to the position's current `debt` (loan-token units) from `/v1/data/lending/user-positions` and approve exactly that to the Midnight core. To **fully close and reclaim collateral**, repay the debt and then withdraw the collateral via [`/v1/actions/lending/withdraw`](/1delta-api/lending-withdraw) — collateral cannot be freed while any debt remains.\n\n**Teller markets (`TELLER_<pool>`):** pass `posId` = the `bidId` to repay (from the user-positions `term.loanId`). A **full** repay (`isAll`, or an `amount` ≥ the amount owed) uses `repayLoanFull` which repays principal + interest **and releases ALL the bid's collateral** — Teller has no keep-collateral partial close. A **partial** repay (`amount` < owed) uses `repayLoan` and keeps the collateral escrowed. ⚠ Liquidation is TIME-based and **aggressive**: after the term you have only a **short grace window** (`params.market.teller.paymentDefaultDuration`, as low as 5 min) to roll over or repay — miss it and the loan DEFAULTS, and a liquidator can seize your **ENTIRE collateral** (not just the amount owed). Repay or roll over **before** the deadline; there is no price buffer.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/repay`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `isAll` | query | boolean | no | Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is. |\n| `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `loanId` | query | string | no | **Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay.\n\nPass the `loanId` of the target loan from the user's positions (each per-loan position in the\nuser-positions response carries `loanId` and a `term` object). To repay the flexible /\ndynamic position instead, pass the sentinel `340282366920938463463374607431768211455`\n(`type(uint128).max`).\n\nThe broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed\nloans) and refunds any excess to the caller, so to fully close a loan fund\n`outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`).\n\nRequired on brokered repays; ignored for non-brokered lenders. |\n| `payAsset` | query | string | no | Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is."
          },
          {
            "name": "lendingMode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "loanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "450"
            },
            "description": "**Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay.\n\nPass the `loanId` of the target loan from the user's positions (each per-loan position in the\nuser-positions response carries `loanId` and a `term` object). To repay the flexible /\ndynamic position instead, pass the sentinel `340282366920938463463374607431768211455`\n(`type(uint128).max`).\n\nThe broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed\nloans) and refunds any excess to the caller, so to fully close a loan fund\n`outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`).\n\nRequired on brokered repays; ignored for non-brokered lenders.",
            "example": "450"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata and approvals for repay",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxyResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Repay (simulate)",
        "description": "Build calldata for repaying a loan and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/lending/repay`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). |\n| `amount` | query | string | yes | Amount in wei |\n| `mode` | query | `proxy`, `direct` | no | Execution mode. proxy = 1delta composer, direct = raw protocol |\n| `operator` | query | string | no | Wallet address of the user executing the action |\n| `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). |\n| `isAll` | query | boolean | no | Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is. |\n| `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `loanId` | query | string | no | **Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay.\n\nPass the `loanId` of the target loan from the user's positions (each per-loan position in the\nuser-positions response carries `loanId` and a `term` object). To repay the flexible /\ndynamic position instead, pass the sentinel `340282366920938463463374607431768211455`\n(`type(uint128).max`).\n\nThe broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed\nloans) and refunds any excess to the caller, so to fully close a loan fund\n`outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`).\n\nRequired on brokered repays; ignored for non-brokered lenders. |\n| `payAsset` | query | string | no | Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. |\n| `isShares` | query | boolean | no | Amount is in shares (direct mode) |\n| `accountId` | query | string | no | Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). |\n| `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender). |\n| `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Simulation results including projected health factor and borrow capacity |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "proxy",
                "direct"
              ],
              "default": "direct"
            },
            "description": "Execution mode. proxy = 1delta composer, direct = raw protocol"
          },
          {
            "name": "operator",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Wallet address of the user executing the action",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw).\nDefaults to `operator` when omitted.\n\nCustom-receiver support is per-lender. The API auto-selects the execution path:\n\n**Direct path supported**\n\n- Aave V2/V3 — `supply` / `withdraw` honor `to`.\n- Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing \"giver\".\n- Compound V3 — `supplyTo` / `withdrawTo`.\n- Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`.\n- Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers.\n- Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`.\n- Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`.\n- Fluid borrow & withdraw — `operate(..., to_)` outflow slot.\n- Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership).\n\n**Routes to composer (proxy) path**\n\n- Compound V2 family — direct `mint` is `msg.sender`-only.\n- Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot.\n- Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`.\n\n**Direct-only branches that throw**\n\n- Gearbox V3 credit-side `addCollateral` — CA bound to operator.\n- Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot.\n\n**Unsupported in any single tx**\n\n- Init Capital — position NFT swept to operator.\n- Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.\n- Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).\n\nWhen the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Withdraw/repay full balance.\n\nWhen on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode:\n\n- If `amount` covers the full position the action is treated as \"withdraw/repay all\" regardless of this flag.\n- If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts.\n\nWithout on-chain data, the flag is trusted as-is."
          },
          {
            "name": "lendingMode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "loanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "450"
            },
            "description": "**Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay.\n\nPass the `loanId` of the target loan from the user's positions (each per-loan position in the\nuser-positions response carries `loanId` and a `term` object). To repay the flexible /\ndynamic position instead, pass the sentinel `340282366920938463463374607431768211455`\n(`type(uint128).max`).\n\nThe broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed\nloans) and refunds any excess to the caller, so to fully close a loan fund\n`outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`).\n\nRequired on brokered repays; ignored for non-brokered lenders.",
            "example": "450"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with.\n\nUse the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets).\n\nProxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Amount is in shares (direct mode)"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position identifier. Lender-specific:\n\n- **Init Capital** — account ID, required for borrow/withdraw/repay.\n- **Euler V2** — sub-account index (0..255), defaults to 0.\n- **Gearbox V3** — credit-account address (alias: `creditAccount`).\n- **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation)."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%).\n\nRequired whenever the action has to price something:\n\n- **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the\n  market's underlying, the currency conversion is routed through a DEX\n  aggregator and this bounds that swap.\n- **Order-book take (Morpho Midnight)** — bounds the worst execution price\n  accepted while filling offers.\n\nIgnored when neither applies (same-asset action on a pool lender).",
            "example": 50
          },
          {
            "name": "simulate",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction calldata with post-trade simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/LendingRawSimulationResponse"
                        },
                        {
                          "$ref": "#/components/schemas/LendingProxySimulationResponse"
                        }
                      ],
                      "description": "Simulation results including projected health factor and borrow capacity"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "repay-simulate"
      }
    },
    "/v1/actions/lending/mode": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Switch mode",
        "description": "Build calldata for switching the active risk-category (\"mode\") on a lender that supports it (e.g. Aave V3 e-mode).\n\nThe \"mode\" terminology is the protocol-agnostic generalization of Aave V3's \"e-mode\" (efficiency mode); other lenders expose analogous category mechanisms.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/mode`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. |\n| `mode` | query | integer | yes | Target mode category ID |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3"
            },
            "description": "Protocol identifier See the `LenderId` schema for the full set of accepted values.",
            "example": "AAVE_V3"
          },
          {
            "name": "mode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "example": 1
            },
            "description": "Target mode category ID",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "$ref": "#/components/schemas/LendingRawResponse",
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "switch-mode"
      }
    },
    "/v1/actions/lending/enable-collateral": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Enable/disable collateral",
        "description": "Build calldata for toggling an asset as collateral. Supported on lenders with explicit collateral toggles (Aave V2/V3, Compound V2 via `enterMarkets`/`exitMarket`); other lenders return a 400. Identify the market via `marketUid` (format: `lender:chainId:address`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/enable-collateral`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave) or cToken (CompoundV2). |\n| `enabled` | query | boolean | yes | true to enable, false to disable |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave) or cToken (CompoundV2).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "enabled",
            "in": "query",
            "required": true,
            "schema": {
              "type": "boolean",
              "example": true
            },
            "description": "true to enable, false to disable",
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "$ref": "#/components/schemas/LendingRawResponse",
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "enable-disable-collateral"
      }
    },
    "/v1/actions/lending/repay-with-atoken": {
      "get": {
        "tags": [
          "Lending (Actions)"
        ],
        "summary": "Repay with aToken",
        "description": "Build calldata for repaying a loan using aTokens on Aave V3. Other lenders return a 400. Identify the market via `marketUid` (format: `lender:chainId:address`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/lending/repay-with-atoken`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token. |\n| `amount` | query | string | yes | Amount in wei |\n| `lendingMode` | query | string | no | Interest rate mode (default: VARIABLE) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier (`lender:chainId:address`). The address encodes the underlying token.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "lendingMode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Interest rate mode (default: VARIABLE)"
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "$ref": "#/components/schemas/LendingRawResponse",
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "repay-with-atoken"
      }
    },
    "/v1/actions/loop/leverage": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Leverage (loop)",
        "description": "Open a leveraged position via borrow → swap → deposit. Identify the debt market with `marketUidIn` and collateral market with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`).\n\n**Response `actions` fields (when `account` is provided):**\n- `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute.\n- `transactions`: Pre-trade setup — mode/e-mode switch (Aave V3) or collateral enable (Venus). Empty if not needed.\n- `permissions`: ERC20 approvals (targeting the composer contract) and lender borrow delegations (targeting the lending protocol contract). Only missing approvals are returned. Execute these first.\n\n**Lista DAO fixed-term (brokered) markets:** when `marketUidIn` is brokered, pass `termId` to open the loop's debt leg as a fixed-term broker loan. The collateral deposit leg is handled automatically (routed through the market's `collateralProvider` when set, e.g. slisBNB). Closing such a loop requires the loan's `loanId` on `/v1/actions/loop/close`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/leverage`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `debtAmount` | query | string | yes | Debt amount in wei |\n| `payAsset` | query | string | no | Asset to pay with (optional zap-in asset) |\n| `payAmount` | query | string | no | Pay amount in wei |\n| `leverage` | query | number | no | Target leverage multiplier |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `borrowMode` | query | `0`, `1`, `2` | no | Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `termId` | query | integer | no | **Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for\nthe loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`).\nRequired when `marketUidIn` is a brokered market — the borrow leg routes through the broker;\nignored otherwise. |\n| `accountId` | query | string | no | Account ID (Init Capital) |\n| `selectedMode` | query | integer | no | Position mode for new positions (Init Capital) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "debtAmount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Debt amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with (optional zap-in asset)"
          },
          {
            "name": "payAmount",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Pay amount in wei"
          },
          {
            "name": "leverage",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Target leverage multiplier"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "borrowMode",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "termId",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 1
            },
            "description": "**Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for\nthe loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`).\nRequired when `marketUidIn` is a brokered market — the borrow leg routes through the broker;\nignored otherwise.",
            "example": 1
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID (Init Capital)"
          },
          {
            "name": "selectedMode",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Position mode for new positions (Init Capital)"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote or full build response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "leverage-loop"
      },
      "post": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Leverage loop (simulate)",
        "description": "Open a leveraged position and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/loop/leverage`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `debtAmount` | query | string | yes | Debt amount in wei |\n| `payAsset` | query | string | no | Asset to pay with (optional zap-in asset) |\n| `payAmount` | query | string | no | Pay amount in wei |\n| `leverage` | query | number | no | Target leverage multiplier |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `borrowMode` | query | `0`, `1`, `2` | no | Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE) |\n| `termId` | query | integer | no | **Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for\nthe loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`).\nRequired when `marketUidIn` is a brokered market — the borrow leg routes through the broker;\nignored otherwise. |\n| `accountId` | query | string | no | Account ID (Init Capital) |\n| `selectedMode` | query | integer | no | Position mode for new positions (Init Capital) |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Quotes and simulation results |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "debtAmount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Debt amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Asset to pay with (optional zap-in asset)"
          },
          {
            "name": "payAmount",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Pay amount in wei"
          },
          {
            "name": "leverage",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Target leverage multiplier"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "borrowMode",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE)"
          },
          {
            "name": "termId",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 1
            },
            "description": "**Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for\nthe loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`).\nRequired when `marketUidIn` is a brokered market — the borrow leg routes through the broker;\nignored otherwise.",
            "example": 1
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID (Init Capital)"
          },
          {
            "name": "selectedMode",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Position mode for new positions (Init Capital)"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote or full build with simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginSimulationQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginSimulationBuildResponse"
                        }
                      ],
                      "description": "Quotes and simulation results"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "leverage-loop-simulate"
      }
    },
    "/v1/actions/loop/close": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Close margin position",
        "description": "Close a leveraged position. Identify the collateral market with `marketUidIn` and debt market with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`).\n\n**Response `actions` fields (when `account` is provided):**\n- `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute.\n- `transactions`: Empty for close operations (no setup needed).\n- `permissions`: Lender withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first.\n\n**Lista DAO fixed-term (brokered) markets:** when `marketUidOut` is brokered, pass `loanId` to select which broker loan the repay leg pays down (or the `type(uint128).max` sentinel for the flexible position). The collateral withdraw leg is handled automatically (routed through the market's `collateralProvider` when set, e.g. slisBNB).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) |\n| `irModeOut` | query | `0`, `1`, `2` | no | Interest rate mode for debt |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Repay full debt |\n| `loanId` | query | string | no | **Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays\non the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response,\nor the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the\nflexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise. |\n| `accountId` | query | string | no | Account ID |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT)"
          },
          {
            "name": "irModeOut",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for debt"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Repay full debt"
          },
          {
            "name": "loanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "450"
            },
            "description": "**Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays\non the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response,\nor the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the\nflexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise.",
            "example": "450"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote or full build response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "close-margin-position"
      },
      "post": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Close position (simulate)",
        "description": "Close a leveraged position and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/loop/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) |\n| `irModeOut` | query | `0`, `1`, `2` | no | Interest rate mode for debt |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Repay full debt |\n| `loanId` | query | string | no | **Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays\non the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response,\nor the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the\nflexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise. |\n| `accountId` | query | string | no | Account ID |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Quotes and simulation results |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT)"
          },
          {
            "name": "irModeOut",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for debt"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Repay full debt"
          },
          {
            "name": "loanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "450"
            },
            "description": "**Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays\non the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response,\nor the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the\nflexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise.",
            "example": "450"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote or full build with simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginSimulationQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginSimulationBuildResponse"
                        }
                      ],
                      "description": "Quotes and simulation results"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "close-position-simulate"
      }
    },
    "/v1/actions/loop/refinance": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Refinance / roll-over (move debt to a fixed term)",
        "description": "Move a user's fixed-term debt into a fresh term — \"refinance\" / \"roll-over\".\n\nServes **two** lenders, each with its own mechanism (the response shape is the same: a transaction plus its permissions):\n\n- **Lista DAO brokered markets** — a flash-loan-backed 1delta composer bundle (repay the source loan, open the new fixed loan).\n- **Exactly** — the protocol's OWN periphery (`DebtManager` on Optimism, `DebtRoller` on Base): ONE direct transaction that flash-loans from Balancer, repays the source position and re-borrows into the target. Because it acts on `msg.sender`'s own position it must be sent by the borrower, and it needs a Market **borrow allowance** (returned as a permission). Maps `fromLoanId` → source maturity and `termId` → target maturity, with `termId=0` meaning \"roll into the variable/floating position\" and an absent `fromLoanId` meaning \"roll FROM the floating position\". Base ships only the fixed→fixed direction. The response adds an `exactly` block (`direction`, `percentage`, `rolledAssets`, `projectedFaceValue`).\n\n\n- **Refinance** (default, omit `fromLoanId`): roll the **dynamic/float** position into a fixed term — e.g. an expired fixed loan the keeper rolled into the dynamic bracket. Lista's own `refinanceMaturedFixedPositions` (matured fixed → dynamic) is keeper-only; this is the user-driven inverse.\n- **Roll-over** (`fromLoanId` = a fixed loan's posId): roll one **fixed** loan into a different term (rate/duration). Rolling a not-yet-matured fixed loan repays it early, so `amount` must also cover its accrued interest + early-repayment penalty.\n\nSame collateral, same principal, different rate bracket.\n\n**Flash-loan backed** (robust at any LTV). The flash comes free from the market's own Moolah singleton, and the new fixed loan repays it. The returned transaction is a single composer bundle:\n```\nflashLoan(loanToken, amount) from Moolah:\n  approve loanToken → Moolah            # so Moolah can pull the flash repayment\n  broker.repay(amount, DYNAMIC, user)   # repay the float position with the flashed funds\n  broker.borrow(amount, termId, user, receiver=composer)  # open the new fixed loan; repays the flash\n→ sweep residual loanToken back to user\n```\nBecause the dynamic is repaid **before** the fixed borrow, the borrow's health check sees the original (net) debt — no 2× peak — so it works regardless of LTV.\n\nNet debt is unchanged. A `setAuthorization(composer)` permission (on Moolah) is returned **only when the composer isn't already authorized** — the broker's on-behalf borrow requires it, but `setAuthorization` reverts `AlreadySet()` if re-applied, so the server reads `isAuthorized(user, composer)` on-chain and omits the permission when it's already set. `actions.permissions` is empty in that case.\n\n**Notes:**\n- Single-market, debt-side only — pass the **loan-token** `marketUid` of a brokered market.\n- **Full close (default — omit `amount`):** the server sizes the flash to the source loan's borrow balance + a small (0.05%) margin, clearing it to zero (the broker refunds the margin, swept back). The balance is the **max** of (a) the `borrowBalance` you POST in the body and (b) a fresh on-chain read — robust whether or not the worker's live RPC is current. Avoids the `REMAIN_BORROW_TOO_LOW` revert from a stale client snapshot `amount`. **Prefer POST** with `borrowBalance` (+ `earlyRepayPenalty` for a not-yet-matured fixed source) from `/v1/data/lending/user-positions`; a plain GET also works (on-chain read only). Never make the user hand-pick an over-funded amount.\n- **Partial re-fix:** pass an explicit `amount` (leave `isAll` unset) < the source outstanding. Both the new fixed (`amount`) and the remaining source must clear `minLoan`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/refinance`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUid` | query | string | yes | Loan-token market identifier of a Lista brokered market (`lender:chainId:address`). |\n| `amount` | query | string | no | Flash / repay / new-fixed amount (loan-token wei). **Required only for a partial re-fix** (provide `amount`, leave `isAll` unset). For a full close, omit it — the server sizes the flash itself; if present alongside a full close it is used only as a floor hint. |\n| `isAll` | query | boolean | no | Force a full close even when `amount` is present. A full close is also the DEFAULT whenever `amount` is omitted. The server sizes the flash to the source loan's borrow balance — the max of the POST-body `borrowBalance` (+ `earlyRepayPenalty`) and a fresh on-chain read (dynamic = `getUserTotalDebt` minus each fixed position's current debt; fixed = that position's current debt + early-repay penalty) — plus a small (0.05%) margin. The repay clears the source to zero and the broker refunds the margin (swept back), so there is no sub-`minLoan` dust and no `REMAIN_BORROW_TOO_LOW`. Set `amount` (and leave this unset) only for a deliberate partial re-fix. |\n| `termId` | query | integer | yes | Fixed term to move the debt into, from the market's `terms[]` rate card (`MarketTerm.termId`). |\n| `fromLoanId` | query | string | no | Source loan to roll FROM: a fixed loan's `loanId` (posId) to roll one fixed loan into another term, or omit (defaults to `type(uint128).max`) to refinance the dynamic/float position. |\n| `operator` | query | string | yes | The borrower (and tx sender). Both the repaid source loan and the new fixed loan are this account. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `borrowBalance` | string | no | Source loan's current borrow balance (loan-token wei). |\n| `earlyRepayPenalty` | string | no | Source loan's early-repay penalty (loan-token wei) — fixed, not-yet-matured source only. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Response from proxy-mode lending operations (via 1delta composer). |\n| `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.transaction.to` | string | Target contract address |\n| `data.transaction.data` | string | Encoded calldata |\n| `data.transaction.value` | string | ETH value to send with the transaction |\n| `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"transaction\": {\n      \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"0\",\n      \"description\": \"string\"\n    },\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": false,
          "description": "Optional source-loan position data for sizing a full close (sent as POST). When provided, the server sizes the flash to the **max** of this `borrowBalance` (+ `earlyRepayPenalty`) and a fresh on-chain read, plus a small margin — so it never depends solely on the worker's live RPC. Pass the source loan's current debt from `/v1/data/lending/user-positions`. Ignored for a partial re-fix (explicit `amount`, `isAll` unset).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "borrowBalance": {
                    "type": "string",
                    "description": "Source loan's current borrow balance (loan-token wei).",
                    "example": "100030000000000000"
                  },
                  "earlyRepayPenalty": {
                    "type": "string",
                    "description": "Source loan's early-repay penalty (loan-token wei) — fixed, not-yet-matured source only.",
                    "example": "0"
                  }
                }
              },
              "example": {
                "borrowBalance": "100030000000000000",
                "earlyRepayPenalty": "0"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "marketUid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "LISTA_DAO_226935…3cac:56:0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"
            },
            "description": "Loan-token market identifier of a Lista brokered market (`lender:chainId:address`).",
            "example": "LISTA_DAO_226935…3cac:56:0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"
          },
          {
            "name": "amount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "50000000000000000"
            },
            "description": "Flash / repay / new-fixed amount (loan-token wei). **Required only for a partial re-fix** (provide `amount`, leave `isAll` unset). For a full close, omit it — the server sizes the flash itself; if present alongside a full close it is used only as a floor hint.",
            "example": "50000000000000000"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean",
              "example": "true"
            },
            "description": "Force a full close even when `amount` is present. A full close is also the DEFAULT whenever `amount` is omitted. The server sizes the flash to the source loan's borrow balance — the max of the POST-body `borrowBalance` (+ `earlyRepayPenalty`) and a fresh on-chain read (dynamic = `getUserTotalDebt` minus each fixed position's current debt; fixed = that position's current debt + early-repay penalty) — plus a small (0.05%) margin. The repay clears the source to zero and the broker refunds the margin (swept back), so there is no sub-`minLoan` dust and no `REMAIN_BORROW_TOO_LOW`. Set `amount` (and leave this unset) only for a deliberate partial re-fix.",
            "example": "true"
          },
          {
            "name": "termId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "example": 1
            },
            "description": "Fixed term to move the debt into, from the market's `terms[]` rate card (`MarketTerm.termId`).",
            "example": 1
          },
          {
            "name": "fromLoanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "450"
            },
            "description": "Source loan to roll FROM: a fixed loan's `loanId` (posId) to roll one fixed loan into another term, or omit (defaults to `type(uint128).max`) to refinance the dynamic/float position.",
            "example": "450"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "The borrower (and tx sender). Both the repaid source loan and the new fixed loan are this account.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          }
        ],
        "responses": {
          "200": {
            "description": "Flash-loan composer transaction (repay source loan + borrow new fixed term) and the borrow-authorization permission",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "$ref": "#/components/schemas/LendingProxyResponse",
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "transaction": {
                      "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "0",
                      "description": "string"
                    },
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "refinance-roll-over-move-debt-to-a-fixed-term"
      }
    },
    "/v1/actions/loop/collateral-swap": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Collateral swap",
        "description": "Swap collateral assets within a lending position. Identify the sell-side collateral market with `marketUidIn` and buy-side with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`).\n\n**Response `actions` fields (when `account` is provided):**\n- `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute.\n- `transactions`: Collateral enable (`enterMarkets`) for Compound V2 lenders. Empty otherwise.\n- `permissions`: Lender withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/collateral-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Swap full collateral balance |\n| `accountId` | query | string | no | Account ID |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Swap full collateral balance"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote or full build response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "collateral-swap"
      },
      "post": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Collateral swap (simulate)",
        "description": "Swap collateral assets and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\nFor `isAll` trades, include `depositBalanceIn` (raw underlying balance string) in the body so the withdrawal approval is sized to the actual position. This field is accepted alongside or independently of the simulation fields.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/loop/collateral-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Swap full collateral balance |\n| `accountId` | query | string | no | Account ID |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n| `depositBalanceIn` | string | no | Raw deposit balance of the input collateral asset in underlying units. Used for isAll to size the withdrawal approval correctly. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Quotes and simulation results |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Swap full collateral balance"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. Accepts standard SimulationBody fields and/or `depositBalanceIn` (raw balance string) for accurate isAll withdrawal approvals.",
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/SimulationBody"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "depositBalanceIn": {
                        "type": "string",
                        "description": "Raw deposit balance of the input collateral asset in underlying units. Used for isAll to size the withdrawal approval correctly.",
                        "example": "1000000000000000000"
                      }
                    }
                  }
                ]
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ],
                "depositBalanceIn": "1000000000000000000"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote or full build with simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginSimulationQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginSimulationBuildResponse"
                        }
                      ],
                      "description": "Quotes and simulation results"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "collateral-swap-simulate"
      }
    },
    "/v1/actions/loop/debt-swap": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Debt swap",
        "description": "Swap debt between different borrow positions. Identify the repay-side debt market with `marketUidIn` and borrow-side with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`).\n\n**Response `actions` fields (when `account` is provided):**\n- `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute.\n- `transactions`: Empty for debt-swap operations (no setup needed).\n- `permissions`: Lender borrow and withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/debt-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type |\n| `irModeIn` | query | `0`, `1`, `2` | no | Interest rate mode for repaid debt |\n| `irModeOut` | query | `0`, `1`, `2` | no | Interest rate mode for new debt |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Repay full debt |\n| `accountId` | query | string | no | Account ID |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type"
          },
          {
            "name": "irModeIn",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for repaid debt"
          },
          {
            "name": "irModeOut",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for new debt"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Repay full debt"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote or full build response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "debt-swap"
      },
      "post": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Debt swap (simulate)",
        "description": "Swap debt between borrow positions and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/loop/debt-swap`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). |\n| `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `amount` | query | string | yes | Amount in wei |\n| `tradeType` | query | `0`, `1` | no | Trade type |\n| `irModeIn` | query | `0`, `1`, `2` | no | Interest rate mode for repaid debt |\n| `irModeOut` | query | `0`, `1`, `2` | no | Interest rate mode for new debt |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n| `isAll` | query | boolean | no | Repay full debt |\n| `accountId` | query | string | no | Account ID |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `balanceData` | object | yes | Aggregated balance data for a sub-account. |\n| `balanceData.deposits` | number | no | Total deposits in USD |\n| `balanceData.debt` | number | no | Total debt in USD |\n| `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors |\n| `balanceData.collateral` | number | no | Collateral value in USD |\n| `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled |\n| `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors |\n| `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled |\n| `balanceData.nav` | number | no | Net asset value (deposits - debt) |\n| `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) |\n| `balanceData.debt24h` | number | no | Debt 24h ago |\n| `balanceData.nav24h` | number | no | NAV 24h ago |\n| `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. |\n| `balanceData.rewards[].asset` | string | no | Reward token contract address |\n| `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) |\n| `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) |\n| `aprData` | object | yes | APR breakdown for a sub-account. |\n| `aprData.apr` | number | no | Net APR (deposit - borrow) |\n| `aprData.depositApr` | number | no | Weighted deposit APR |\n| `aprData.borrowApr` | number | no | Weighted borrow APR |\n| `aprData.rewardApr` | number | no | Total reward APR |\n| `aprData.rewardDepositApr` | number | no | Reward APR on deposits |\n| `aprData.rewardBorrowApr` | number | no | Reward APR on borrows |\n| `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) |\n| `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits |\n| `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows |\n| `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. |\n| `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to \"0\") |\n| `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. |\n| `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) |\n| `positions[].depositsUSD` | number | yes | Deposit amount in USD |\n| `positions[].debtUSD` | number | yes | Variable debt in USD |\n| `positions[].debtStableUSD` | number | yes | Stable debt in USD |\n| `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Quotes and simulation results |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.simulation` | object | Projected post-trade metrics, or null if simulation failed |\n| `data.simulation.pre` | object | Portfolio state before the trade. |\n| `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) |\n| `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade |\n| `data.simulation.post` | object | Projected portfolio state after the trade. |\n| `data.simulation.post.healthFactor` | number | Projected health factor after the trade |\n| `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade |\n| `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. |\n| `data.simulation.post.aprData` | object | APR breakdown for a sub-account. |\n| `data.simulationError` | string | Error message if simulation failed |\n| `data.lender` | string | Protocol identifier. See the `LenderId` schema. |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ],\n    \"simulation\": {\n      \"pre\": {\n        \"healthFactor\": 1.85,\n        \"borrowCapacity\": 3000\n      },\n      \"post\": {\n        \"healthFactor\": 2.1,\n        \"borrowCapacity\": 3500,\n        \"balanceData\": {\n          \"deposits\": 10000.5,\n          \"debt\": 5000.25,\n          \"adjustedDebt\": 5500,\n          \"collateral\": 9000,\n          \"collateralAllActive\": 10000.5,\n          \"borrowDiscountedCollateral\": 8000,\n          \"borrowDiscountedCollateralAllActive\": 9000,\n          \"nav\": 5000.25,\n          \"deposits24h\": 9800,\n          \"debt24h\": 4900,\n          \"nav24h\": 4900,\n          \"rewards\": [\n            {\n              \"asset\": \"0xc00e94Cb662C3520282E6f5717214004A7f26888\",\n              \"totalRewards\": 12.5,\n              \"claimableRewards\": 12.5\n            }\n          ]\n        },\n        \"aprData\": {\n          \"apr\": 2.5,\n          \"depositApr\": 3.5,\n          \"borrowApr\": 5.2,\n          \"rewardApr\": 1.2,\n          \"rewardDepositApr\": 0.8,\n          \"rewardBorrowApr\": 0.4,\n          \"intrinsicApr\": 0,\n          \"intrinsicDepositApr\": 0,\n          \"intrinsicBorrowApr\": 0,\n          \"rewards\": {}\n        }\n      }\n    },\n    \"simulationError\": \"string\"\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Market identifier for input side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
            },
            "description": "Market identifier for output side (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type"
          },
          {
            "name": "irModeIn",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for repaid debt"
          },
          {
            "name": "irModeOut",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Interest rate mode for new debt"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Repay full debt"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Account ID"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional current portfolio state for post-trade simulation. If omitted, the API fetches balances on-chain automatically (slower, no `simulation` in response). When provided, pass `balanceData`, `aprData`, and `positions` directly from the matching sub-account in the `/v1/data/lending/user-positions` response — see the `SimulationBody` schema for a step-by-step example.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulationBody"
              },
              "example": {
                "balanceData": {
                  "deposits": 10000.5,
                  "debt": 5000.25,
                  "adjustedDebt": 5500,
                  "collateral": 9000,
                  "collateralAllActive": 10000.5,
                  "borrowDiscountedCollateral": 8000,
                  "borrowDiscountedCollateralAllActive": 9000,
                  "nav": 5000.25,
                  "deposits24h": 9800,
                  "debt24h": 4900,
                  "nav24h": 4900,
                  "rewards": [
                    {
                      "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                      "totalRewards": 12.5,
                      "claimableRewards": 12.5
                    }
                  ]
                },
                "aprData": {
                  "apr": 2.5,
                  "depositApr": 3.5,
                  "borrowApr": 5.2,
                  "rewardApr": 1.2,
                  "rewardDepositApr": 0.8,
                  "rewardBorrowApr": 0.4,
                  "intrinsicApr": 0,
                  "intrinsicDepositApr": 0,
                  "intrinsicBorrowApr": 0,
                  "rewards": {}
                },
                "modeId": "0",
                "positions": [
                  {
                    "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
                    "depositsUSD": 5000,
                    "debtUSD": 2000,
                    "debtStableUSD": 0,
                    "collateralEnabled": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote or full build with simulation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginSimulationQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginSimulationBuildResponse"
                        }
                      ],
                      "description": "Quotes and simulation results"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ],
                    "simulation": {
                      "pre": {
                        "healthFactor": 1.85,
                        "borrowCapacity": 3000
                      },
                      "post": {
                        "healthFactor": 2.1,
                        "borrowCapacity": 3500,
                        "balanceData": {
                          "deposits": 10000.5,
                          "debt": 5000.25,
                          "adjustedDebt": 5500,
                          "collateral": 9000,
                          "collateralAllActive": 10000.5,
                          "borrowDiscountedCollateral": 8000,
                          "borrowDiscountedCollateralAllActive": 9000,
                          "nav": 5000.25,
                          "deposits24h": 9800,
                          "debt24h": 4900,
                          "nav24h": 4900,
                          "rewards": [
                            {
                              "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
                              "totalRewards": 12.5,
                              "claimableRewards": 12.5
                            }
                          ]
                        },
                        "aprData": {
                          "apr": 2.5,
                          "depositApr": 3.5,
                          "borrowApr": 5.2,
                          "rewardApr": 1.2,
                          "rewardDepositApr": 0.8,
                          "rewardBorrowApr": 0.4,
                          "intrinsicApr": 0,
                          "intrinsicDepositApr": 0,
                          "intrinsicBorrowApr": 0,
                          "rewards": {}
                        }
                      }
                    },
                    "simulationError": "string"
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "debt-swap-simulate"
      }
    },
    "/v1/actions/loop/migrate": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Migrate position (cross-lender)",
        "operationId": "loop-migrate",
        "description": "Move a whole debt + collateral position from one lender to another in a single flash-loan transaction, optionally converting ONE leg (collateral OR debt) via an aggregator swap.\n\nFlow (no conversion): flash the debt → repay the source → withdraw the source collateral → deposit it to the target → borrow the debt from the target → repay the flash. Same-lender / different-market moves (e.g. Morpho market A→B, Aave V4 reserve→reserve) are supported.\n\n**Supported sources & targets:** Aave V2/V3, Aave V4, Compound V3, Morpho Blue / Lista, Fluid (an existing position via NFT-custody, OR a brand-new position — see below), Gearbox V3 (existing credit account as source; a fresh credit account is opened in-callback as target), Euler V2 (accountId 0; collateral-share transfer through the call forwarder). **Not supported:** Dolomite (either side), Euler as a TARGET, non-Venus Compound V2 as a target, both legs converting at once, Fluid↔Fluid.\n\n> **Fluid target — existing vs fresh:** pass the position's NFT id in `accountId` to migrate INTO an existing Fluid position (delivered via the VaultFactory NFT-custody flow). Omit it (or pass 0) to open a **brand-new** Fluid position: the migrate emits a single dual-axis Fluid `operate` that supplies the withdrawn collateral, borrows the debt, and mints the new position NFT straight to you — no NFT custody, no target-side consent, and the transaction targets the composer (`deltaCompose`) normally.\n\n> **Native ↔ wrapped-native (wrap conversion):** a native debt — e.g. a Venus `vBNB` borrow — migrates into a target lender's **wrapped-native** debt market (WBNB). On-behalf borrowing cannot be delegated for the native asset, so the target MUST be the wrapped form; a native TARGET debt is rejected. The builder flashes the wrapped form, unwraps it to repay the native source, and borrows the wrapped form on the target — no aggregator needed. Compound V2 / Venus can be a migration **source** but never a **target** (no borrow delegation). The **collateral** leg wraps BOTH ways — a native source collateral (e.g. Fluid's ETH slot) is wrapped to WETH before the target deposit, and a wrapped source collateral is unwrapped for a native-collateral target — again with no aggregator. Native collateral is only reachable as such a wrap pair; native → an unrelated ERC20 target is rejected.\n\n> **Lista DAO markets:** two per-market extras decide the shape. A **brokered** market (non-zero `broker`) routes its debt leg through the fixed-term broker — pass `loanId` when it is the SOURCE (which loan to repay) and `termId` when it is the TARGET (which term to open); the target has no default because the broker's flexible borrow has no on-behalf variant. A market with a **`collateralProvider`** (e.g. the slisBNB markets) routes its collateral leg through that provider, which exposes no `position()` getter — so a provider-gated SOURCE cannot use the withdraw-all sentinel and is sized from your live collateral balance instead (read server-side; pass `collateralAmount` to override).\n\n> **Asset conversion (swap leg):** ONE leg may change asset via an aggregator swap — either the collateral (`marketUidTargetCollateral` uses a different underlying) or the debt (`marketUidTargetDebt`), not both. The route fetches the aggregator quote server-side and bakes the trade into the flash callback. A **collateral** swap is EXACT_INPUT of the withdrawn collateral → provide a concrete `collateralAmount` (or `collateralAmountHint`) so the swap input lines up. A **debt** swap is EXACT_OUTPUT (buy exactly the source debt to repay, selling the flashed target debt). Tune the swap tolerance with `slippage`. **Euler as a source** still needs an off-chain eVault share-balance read via the `prepareMigrate` SDK.\n\nOmit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`).\n\n**Setup transactions (`actions.permissions`):** returned only for the consents actually missing, to be executed BEFORE the migrate. These vary by lender pair — e.g. the source collateral withdrawal approval; Aave V4 Giver/Taker/Config Position-Manager authorizations + per-reserve borrow allowance + collateral-enable grant; Morpho `setAuthorization`; a Gearbox V3 SOURCE's `setBotPermissions` grant on the credit account; Euler collateral eVault share approval to the composer. Fluid legs need no separate permission (NFT custody — or, for a fresh open, the composer opening on your behalf — IS the authorization).\n\n**Delivery:** the migrate transaction targets the composer (`deltaCompose`) normally, OR the Fluid `VaultFactory.safeTransferFrom` when a Fluid leg requires NFT custody — `actions.transactions[0].to` reflects this.\n\n**`data.result` (resulting position):** a summary for the UI — `from`/`to` lenders with their collateral + debt assets (address/symbol/decimals/logo), the new position amounts (`to.collateral.amount`/`amountUsd`, `to.debt.amount`/`amountUsd`), `netUsd`, `leverage`, `apr: { deposit, borrow, net }` and `healthFactor`. The rates, liquidation threshold, decimals and prices behind those are **resolved server-side** from the target markets — the corresponding query params are overrides only. USD/symbol fields are best-effort (omitted when price/token metadata is unavailable). `to.collateral.amount` is present when the withdraw was sized server-side (Aave source) or passed explicitly.\n\n**Finding a target:** [`GET /v1/actions/loop/migrate/targets`](/1delta-api/loop-migrate-targets) returns the ranked destinations this endpoint accepts for a given position — support matrix, native ⇄ wrapped equivalence, un-openable fixed-term books and borrow liquidity all applied server-side.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/migrate`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidSourceCollateral` | query | string | yes | Source collateral market (`lender:chainId:address`). The position being moved FROM. |\n| `marketUidSourceDebt` | query | string | yes | Source debt market (`lender:chainId:address`). |\n| `marketUidTargetCollateral` | query | string | yes | Target collateral market (`lender:chainId:address`). The position being moved TO. May be a different lender and/or a different asset (collateral conversion). |\n| `marketUidTargetDebt` | query | string | yes | Target debt market (`lender:chainId:address`). May be a different lender and/or a different asset (debt conversion). |\n| `debtAmount` | query | string | yes | Live debt to migrate, in the debt asset’s wei. For a debt conversion this is the NEW-debt (flash/borrow) amount instead. The flash is sized a small buffer above this so the source repay clears in full (a residual would make the full collateral withdrawal revert). |\n| `account` | query | string | no | Account address. Include to build the transaction + permission setup; omit for a quote-only response. |\n| `isMaxIn` | query | boolean | no | Withdraw the full collateral balance from the source (default true for a same-asset move). Set false + `collateralAmount` for an exact-amount conversion so the swap input lines up. |\n| `collateralAmount` | query | string | no | Exact source collateral to withdraw, in wei. Required (with `isMaxIn=false`) for a collateral conversion so the withdrawn amount matches the swap input. |\n| `accountId` | query | string | no | Per-position id where the lender needs one: an existing Fluid NFT id (omit or 0 opens a BRAND-NEW Fluid position), Euler sub-account index (must be 0 — sub-accounts unsupported). Defaults to 0. |\n| `loanId` | query | string | no | Lista fixed-term broker SOURCE only: the loan `posId` to repay, or `type(uint128).max` for the flex/dynamic position. Required when the source debt market is brokered; ignored otherwise. The target borrow is keyed by term, not loanId. |\n| `termId` | query | integer | no | Lista fixed-term broker TARGET only: which term the migrated debt opens at. REQUIRED when the target debt market is brokered — the broker exposes no on-behalf flexible borrow, so there is no default; ignored otherwise. Mirrors the `termId` on /v1/actions/loop/open. |\n| `irModeFrom` | query | `0`, `1`, `2` | no | Aave interest mode of the source debt (repay). 2 = variable. |\n| `irModeTo` | query | `0`, `1`, `2` | no | Aave interest mode of the target debt (borrow). 2 = variable. |\n| `slippage` | query | string | no | Swap-leg slippage tolerance as a FRACTION (`0.005` = 0.5%). Only used\nwhen a leg is converted via an aggregator swap; ignored for same-asset /\nwrap moves. Defaults to 0.5%.\n\n⚠ **This endpoint is the exception.** Every other `slippage` in this API\nis in BASIS POINTS (`50` = 0.5%) — migrate takes a fraction, which is\n100× smaller for the same tolerance. Sending `50` here would ask for\n5000% slippage. |\n| `eModeTo` | query | string | no | Risk-config category to read the TARGET collateral's liquidation threshold from (Aave-style e-modes publish one config per category). Defaults to `0` (no e-mode). Display only — it does not change the built transaction. |\n| `collateralDecimals` | query | integer | no | **Override.** Target collateral decimals. Resolved server-side; pass only to overrule the published metadata (e.g. a market whose token-list decimals are known-wrong, which would mis-scale the `data.result` USD values). Never affects the on-chain amounts. |\n| `debtDecimals` | query | integer | no | **Override.** TARGET debt decimals — the swap target’s when the debt converts, else the source’s. Resolved server-side; see `collateralDecimals`. |\n| `sourceDebtDecimals` | query | integer | no | **Override.** SOURCE debt decimals, for the `from`-leg display when the debt is converted. Resolved server-side; defaults to `debtDecimals`. |\n| `depositApr` | query | string | no | **Override.** Target collateral deposit APR as a FRACTION (0.05 = 5%), intrinsic yield folded in. Resolved server-side and reported as `data.result.apr.deposit`. |\n| `borrowApr` | query | string | no | **Override.** Target debt borrow APR as a FRACTION (0.05 = 5%), intrinsic yield folded in — for a fixed-term target this is the term rate, not the 0% variable rate. Resolved server-side. |\n| `liqThreshold` | query | string | no | **Override.** Target collateral liquidation threshold as a FRACTION (0.85 = 85%), driving `data.result.healthFactor` (= collateralUsd · liqThreshold / debtUsd; < 1 ⇒ liquidatable). Resolved server-side from the target market’s risk config — see `eModeTo`. |\n| `collateralPriceUsd` | query | string | no | **Override.** USD price of the TARGET collateral for the display conversion. Resolved server-side, preferring the market’s own ORACLE price (what the lender liquidates against). |\n| `debtPriceUsd` | query | string | no | **Override.** USD price of the TARGET debt for the display conversion. Resolved server-side; see `collateralPriceUsd`. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. |\n| `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].utilization.current` | number | Current value |\n| `data.rateImpact[].utilization.projected` | number | Projected value after the action |\n| `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].borrowRate.current` | number | Current value |\n| `data.rateImpact[].borrowRate.projected` | number | Projected value after the action |\n| `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. |\n| `data.rateImpact[].depositRate.current` | number | Current value |\n| `data.rateImpact[].depositRate.projected` | number | Projected value after the action |\n| `data.lender` | string | Protocol identifier |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].deltas` | object |  |\n| `data.quotes[].deltas.aggregator` | string | Aggregator source |\n| `data.quotes[].deltas.tradeInput` | number | Trade input amount |\n| `data.quotes[].deltas.tradeOutput` | number | Trade output amount |\n| `data.quotes[].deltas.deltas` | object | Balance deltas |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |\n| `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) |\n| `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"lender\": \"AAVE_V3\",\n    \"quotes\": [\n      {\n        \"deltas\": {\n          \"aggregator\": \"string\",\n          \"tradeInput\": 1.0,\n          \"tradeOutput\": 1.0,\n          \"deltas\": {}\n        },\n        \"rateImpact\": [\n          {\n            \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n            \"utilization\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"borrowRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            },\n            \"depositRate\": {\n              \"current\": 1.0,\n              \"projected\": 1.0\n            }\n          }\n        ]\n      }\n    ],\n    \"rateImpact\": [\n      {\n        \"marketUid\": \"AAVE_V3:8453:0x4200000000000000000000000000000000000006\",\n        \"utilization\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"borrowRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        },\n        \"depositRate\": {\n          \"current\": 1.0,\n          \"projected\": 1.0\n        }\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidSourceCollateral",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Source collateral market (`lender:chainId:address`). The position being moved FROM.",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidSourceDebt",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
            },
            "description": "Source debt market (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
          },
          {
            "name": "marketUidTargetCollateral",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V4_94E7A5DCBE816E498B89AB752661904E2F56C485:1:0"
            },
            "description": "Target collateral market (`lender:chainId:address`). The position being moved TO. May be a different lender and/or a different asset (collateral conversion).",
            "example": "AAVE_V4_94E7A5DCBE816E498B89AB752661904E2F56C485:1:0"
          },
          {
            "name": "marketUidTargetDebt",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V4_94E7A5DCBE816E498B89AB752661904E2F56C485:1:8"
            },
            "description": "Target debt market (`lender:chainId:address`). May be a different lender and/or a different asset (debt conversion).",
            "example": "AAVE_V4_94E7A5DCBE816E498B89AB752661904E2F56C485:1:8"
          },
          {
            "name": "debtAmount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Live debt to migrate, in the debt asset’s wei. For a debt conversion this is the NEW-debt (flash/borrow) amount instead. The flash is sized a small buffer above this so the source repay clears in full (a residual would make the full collateral withdrawal revert).",
            "example": "1000000000"
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build the transaction + permission setup; omit for a quote-only response.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "isMaxIn",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Withdraw the full collateral balance from the source (default true for a same-asset move). Set false + `collateralAmount` for an exact-amount conversion so the swap input lines up."
          },
          {
            "name": "collateralAmount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Exact source collateral to withdraw, in wei. Required (with `isMaxIn=false`) for a collateral conversion so the withdrawn amount matches the swap input.",
            "example": "1000000000000000000"
          },
          {
            "name": "accountId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Per-position id where the lender needs one: an existing Fluid NFT id (omit or 0 opens a BRAND-NEW Fluid position), Euler sub-account index (must be 0 — sub-accounts unsupported). Defaults to 0."
          },
          {
            "name": "loanId",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "340282366920938463463374607431768211455"
            },
            "description": "Lista fixed-term broker SOURCE only: the loan `posId` to repay, or `type(uint128).max` for the flex/dynamic position. Required when the source debt market is brokered; ignored otherwise. The target borrow is keyed by term, not loanId.",
            "example": "340282366920938463463374607431768211455"
          },
          {
            "name": "termId",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 1
            },
            "description": "Lista fixed-term broker TARGET only: which term the migrated debt opens at. REQUIRED when the target debt market is brokered — the broker exposes no on-behalf flexible borrow, so there is no default; ignored otherwise. Mirrors the `termId` on /v1/actions/loop/open.",
            "example": 1
          },
          {
            "name": "irModeFrom",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Aave interest mode of the source debt (repay). 2 = variable."
          },
          {
            "name": "irModeTo",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1,
                2
              ]
            },
            "description": "Aave interest mode of the target debt (borrow). 2 = variable."
          },
          {
            "name": "slippage",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0.005"
            },
            "description": "Swap-leg slippage tolerance as a FRACTION (`0.005` = 0.5%). Only used\nwhen a leg is converted via an aggregator swap; ignored for same-asset /\nwrap moves. Defaults to 0.5%.\n\n⚠ **This endpoint is the exception.** Every other `slippage` in this API\nis in BASIS POINTS (`50` = 0.5%) — migrate takes a fraction, which is\n100× smaller for the same tolerance. Sending `50` here would ask for\n5000% slippage.",
            "example": "0.005"
          },
          {
            "name": "eModeTo",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Risk-config category to read the TARGET collateral's liquidation threshold from (Aave-style e-modes publish one config per category). Defaults to `0` (no e-mode). Display only — it does not change the built transaction.",
            "example": "1"
          },
          {
            "name": "collateralDecimals",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": "8"
            },
            "description": "**Override.** Target collateral decimals. Resolved server-side; pass only to overrule the published metadata (e.g. a market whose token-list decimals are known-wrong, which would mis-scale the `data.result` USD values). Never affects the on-chain amounts.",
            "example": "8"
          },
          {
            "name": "debtDecimals",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": "6"
            },
            "description": "**Override.** TARGET debt decimals — the swap target’s when the debt converts, else the source’s. Resolved server-side; see `collateralDecimals`.",
            "example": "6"
          },
          {
            "name": "sourceDebtDecimals",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": "6"
            },
            "description": "**Override.** SOURCE debt decimals, for the `from`-leg display when the debt is converted. Resolved server-side; defaults to `debtDecimals`.",
            "example": "6"
          },
          {
            "name": "depositApr",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0.031"
            },
            "description": "**Override.** Target collateral deposit APR as a FRACTION (0.05 = 5%), intrinsic yield folded in. Resolved server-side and reported as `data.result.apr.deposit`.",
            "example": "0.031"
          },
          {
            "name": "borrowApr",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0.058"
            },
            "description": "**Override.** Target debt borrow APR as a FRACTION (0.05 = 5%), intrinsic yield folded in — for a fixed-term target this is the term rate, not the 0% variable rate. Resolved server-side.",
            "example": "0.058"
          },
          {
            "name": "liqThreshold",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0.83"
            },
            "description": "**Override.** Target collateral liquidation threshold as a FRACTION (0.85 = 85%), driving `data.result.healthFactor` (= collateralUsd · liqThreshold / debtUsd; < 1 ⇒ liquidatable). Resolved server-side from the target market’s risk config — see `eModeTo`.",
            "example": "0.83"
          },
          {
            "name": "collateralPriceUsd",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1917.56"
            },
            "description": "**Override.** USD price of the TARGET collateral for the display conversion. Resolved server-side, preferring the market’s own ORACLE price (what the lender liquidates against).",
            "example": "1917.56"
          },
          {
            "name": "debtPriceUsd",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0.9998"
            },
            "description": "**Override.** USD price of the TARGET debt for the display conversion. Resolved server-side; see `collateralPriceUsd`.",
            "example": "0.9998"
          }
        ],
        "responses": {
          "200": {
            "description": "Quote or full build response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/MarginQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/MarginBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "lender": "AAVE_V3",
                    "quotes": [
                      {
                        "deltas": {
                          "aggregator": "string",
                          "tradeInput": 1,
                          "tradeOutput": 1,
                          "deltas": {}
                        },
                        "rateImpact": [
                          {
                            "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                            "utilization": {
                              "current": 1,
                              "projected": 1
                            },
                            "borrowRate": {
                              "current": 1,
                              "projected": 1
                            },
                            "depositRate": {
                              "current": 1,
                              "projected": 1
                            }
                          }
                        ]
                      }
                    ],
                    "rateImpact": [
                      {
                        "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
                        "utilization": {
                          "current": 1,
                          "projected": 1
                        },
                        "borrowRate": {
                          "current": 1,
                          "projected": 1
                        },
                        "depositRate": {
                          "current": 1,
                          "projected": 1
                        }
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/loop/migrate/targets": {
      "get": {
        "tags": [
          "Loop (Actions)"
        ],
        "summary": "Migration targets for a position",
        "operationId": "loop-migrate-targets",
        "description": "Which markets can this position migrate to? The discovery companion to [`/v1/actions/loop/migrate`](/1delta-api/loop-migrate) — it returns the ranked set of destinations that endpoint would actually accept, so a client never encodes protocol knowledge to build that list.\n\nGive it the two marketUids of an existing position (and, ideally, its size) and it does everything a caller would otherwise hand-roll:\n\n- **Native ⇄ wrapped-native equivalence.** Some lenders key a market to the native asset (Fluid ETH vaults), others to the wrapped ERC20 (Aave WETH); a migrate bridges them by wrapping. Selection is by shared `assetGroup`, so both forms surface in BOTH directions on every chain — no per-chain WETH table anywhere in the client.\n- **The migrate support matrix.** Lenders that cannot be a target are dropped (Dolomite, Euler, Curvance, LlamaLend and non-Venus Compound V2 forks today). This is the same code path `/migrate` validates with, so the list cannot drift out of sync with what builds.\n- **The native-debt rule.** On-behalf borrowing cannot be delegated for the native asset, so native-debt markets are dropped unless the move is a wrap conversion into Fluid.\n- **Un-openable fixed-term books.** An order-book lender (Morpho Midnight) reports a 0% variable rate and no terms in the pair feed whether its book is rich or empty. Each fixed-term candidate's real borrow term is resolved and the ones that cannot be opened are dropped — 10 of 12 Midnight borrow legs on Base at time of writing. Survivors get `termsShort` back-filled with the true rate + maturity.\n- **Borrow liquidity at this position's size**, applied BEFORE truncation (a client-side filter after paging silently loses real destinations to rows it then discards).\n\n**Rows** come back in the `/v1/data/lending/pairs/optimize` shape, so an existing pair normaliser keeps working, plus a `migrate` block per row:\n\n```jsonc\n\"migrate\": {\n  \"healthFactor\": 1.87,          // collateralUsd · liquidationThreshold / debtUsd on THIS target\n  \"netApr\": 0.041,               // equity-weighted earn − pay for THIS position (not max-leverage aprTotal)\n  \"depositApr\": 0.031,           // effective rates behind netApr (intrinsic yield folded in)\n  \"borrowApr\": 0.058,\n  \"borrowLiquidityUsd\": 6470141,\n  \"sufficientLiquidity\": true,\n  \"maturity\": 1787929200,        // fixed-term targets only\n  \"termHeadline\": \"Fixed 4.01% until 28 Aug 2026\"\n}\n```\n\nThe envelope also carries `source` (the resolved position with its USD values), `hiddenForLiquidity`, and `excluded` — one entry per distinct drop reason, so a UI can explain a short list instead of silently showing one.\n\n> **Native-asset convention.** Every 1delta data payload spells the native asset as the ZERO ADDRESS. `0xEeee…EEeE` is an encoding-layer sentinel: it is accepted on action inputs and normalised away, but it is never served and never matches a data filter. A client filtering markets by `0xEeee…` silently gets no rows.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/loop/migrate/targets`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `marketUidSourceCollateral` | query | string | yes | Collateral market of the position being moved (`lender:chainId:address`). |\n| `marketUidSourceDebt` | query | string | yes | Debt market of the position being moved (`lender:chainId:address`). Must be on the same chain as the collateral. |\n| `debtAmount` | query | string | no | Live debt of the position, in the debt asset’s wei. Supply it to filter out targets that cannot fund the whole borrow, to price each row AT this notional, and to get a resulting health factor per target. |\n| `collateralAmount` | query | string | no | Live collateral of the position, in the collateral asset’s wei. Needed (with `debtAmount`) for the per-target health factor. |\n| `convertLeg` | query | `collateral`, `debt` | no | Ask for targets that CONVERT one leg via an aggregator swap. With `convertTo` omitted the response carries `convertibleAssets` — the assets that leg can convert into while still pairing with the fixed leg — so a picker can be populated without knowing which pairings exist. |\n| `convertTo` | query | string | no | Target asset address for the converted leg. Pins that leg to exactly this asset; the fixed leg keeps the source asset (native ⇄ wrapped-native included). |\n| `count` | query | integer | no | Maximum ranked targets to return (default 50). |\n| `includeIlliquid` | query | boolean | no | Keep targets whose borrow liquidity cannot fund `debtAmount` (they sort last and carry `migrate.sufficientLiquidity: false`). Default false — they are counted in `hiddenForLiquidity` instead. |\n| `maxRiskScore` | query | integer | no | Risk cap for candidate markets. Defaults to `100`, i.e. no cap: a migrate MOVES a position the caller already holds, so the pair browser’s default cap (which hides whole chains) would hide real destinations. Each row still carries its own `risk` breakdown. |\n| `collateralPriceUsd` | query | string | no | **Override.** USD price of the source collateral, for sizing the position. Resolved server-side. |\n| `debtPriceUsd` | query | string | no | **Override.** USD price of the source debt, for sizing the position. Resolved server-side. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "marketUidSourceCollateral",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Collateral market of the position being moved (`lender:chainId:address`).",
            "example": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "marketUidSourceDebt",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
            },
            "description": "Debt market of the position being moved (`lender:chainId:address`). Must be on the same chain as the collateral.",
            "example": "AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
          },
          {
            "name": "debtAmount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Live debt of the position, in the debt asset’s wei. Supply it to filter out targets that cannot fund the whole borrow, to price each row AT this notional, and to get a resulting health factor per target.",
            "example": "1000000000"
          },
          {
            "name": "collateralAmount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Live collateral of the position, in the collateral asset’s wei. Needed (with `debtAmount`) for the per-target health factor.",
            "example": "1000000000000000000"
          },
          {
            "name": "convertLeg",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "collateral",
                "debt"
              ]
            },
            "description": "Ask for targets that CONVERT one leg via an aggregator swap. With `convertTo` omitted the response carries `convertibleAssets` — the assets that leg can convert into while still pairing with the fixed leg — so a picker can be populated without knowing which pairings exist."
          },
          {
            "name": "convertTo",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
            },
            "description": "Target asset address for the converted leg. Pins that leg to exactly this asset; the fixed leg keeps the source asset (native ⇄ wrapped-native included).",
            "example": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
          },
          {
            "name": "count",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Maximum ranked targets to return (default 50)."
          },
          {
            "name": "includeIlliquid",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Keep targets whose borrow liquidity cannot fund `debtAmount` (they sort last and carry `migrate.sufficientLiquidity: false`). Default false — they are counted in `hiddenForLiquidity` instead."
          },
          {
            "name": "maxRiskScore",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Risk cap for candidate markets. Defaults to `100`, i.e. no cap: a migrate MOVES a position the caller already holds, so the pair browser’s default cap (which hides whole chains) would hide real destinations. Each row still carries its own `risk` breakdown."
          },
          {
            "name": "collateralPriceUsd",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "**Override.** USD price of the source collateral, for sizing the position. Resolved server-side."
          },
          {
            "name": "debtPriceUsd",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "**Override.** USD price of the source debt, for sizing the position. Resolved server-side."
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked migration targets for the given position",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/swap/spot": {
      "get": {
        "tags": [
          "Swap"
        ],
        "summary": "Spot swap (meta-aggregator)",
        "description": "Execute a spot swap via the meta-aggregator. Omit `account` for quote-only. Include `account` to build full transaction calldata.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/swap/spot`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `tokenIn` | query | string | yes | Input token address |\n| `tokenOut` | query | string | yes | Output token address |\n| `amount` | query | string | yes | Amount in wei |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. |\n| `receiver` | query | string | no | Receiver address |\n| `tradeType` | query | `0`, `1` | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) |\n| `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.currencyIn` | object | Input currency info |\n| `data.currencyOut` | object | Output currency info |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].aggregator` | string |  |\n| `data.quotes[].tradeInput` | number |  |\n| `data.quotes[].tradeOutput` | number |  |\n| `data.currencyIn` | object | Input currency info |\n| `data.currencyOut` | object | Output currency info |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].aggregator` | string |  |\n| `data.quotes[].tradeInput` | number |  |\n| `data.quotes[].tradeOutput` | number |  |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"currencyIn\": {},\n    \"currencyOut\": {},\n    \"quotes\": [\n      {\n        \"aggregator\": \"string\",\n        \"tradeInput\": 1.0,\n        \"tradeOutput\": 1.0\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "tokenIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
            },
            "description": "Input token address",
            "example": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          },
          {
            "name": "tokenOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
            },
            "description": "Output token address",
            "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei",
            "example": "1000000000000000000"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address. Include to build transaction, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Receiver address"
          },
          {
            "name": "tradeType",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT)"
          },
          {
            "name": "usePendleMintRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Use Pendle mint/redeem"
          }
        ],
        "responses": {
          "200": {
            "description": "Spot swap quote or full build",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/SpotQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/SpotBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "currencyIn": {},
                    "currencyOut": {},
                    "quotes": [
                      {
                        "aggregator": "string",
                        "tradeInput": 1,
                        "tradeOutput": 1
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "spot-swap-meta-aggregator"
      }
    },
    "/v1/actions/swap/x-chain": {
      "get": {
        "tags": [
          "Swap"
        ],
        "summary": "Cross-chain swap (bridge aggregation)",
        "description": "Quote a cross-chain swap across all supported bridge aggregators (Across, LI.FI, Squid, Stargate, Symbiosis, XY Finance, DZap, …) and build the winning transactions. Omit `account` for quote-only. Include `account` to build full transaction calldata. Each build quote carries `approvalTarget`/`approvalRequired`, and `actions.permissions` holds one ERC-20 approve per unique spender (composed routes share the 1delta composer; plain bridges use their own deposit contract) with a `spender` field — execute only the permission whose `spender` equals your chosen quote's `approvalTarget`. When `fromChainId` equals `toChainId` the request falls back to the spot meta-aggregator (same response shape with `aggregator` instead of `bridge` per quote, marked `fallback: 'spot'`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/swap/x-chain`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `fromChainId` | query | string | yes | Source chain ID |\n| `toChainId` | query | string | yes | Destination chain ID |\n| `tokenIn` | query | string | yes | Input token address on the source chain (zero address for native) |\n| `tokenOut` | query | string | yes | Output token address on the destination chain (zero address for native) |\n| `amount` | query | string | yes | Input amount in wei |\n| `slippage` | query | number | yes | Slippage tolerance (basis points) |\n| `account` | query | string | no | Account address on the source chain. Include to build transactions, omit for quote-only. |\n| `receiver` | query | string | no | Receiver address on the destination chain (defaults to account) |\n| `order` | query | `CHEAPEST`, `FASTEST` | no | Route preference |\n| `bridges` | query | string | no | Comma-separated bridge filter (e.g. `Across,LI.FI`). Defaults to all supported bridges. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `data.currencyIn` | object | Input currency info (source chain) |\n| `data.currencyOut` | object | Output currency info (destination chain) |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].bridge` | string |  |\n| `data.quotes[].tradeInput` | number |  |\n| `data.quotes[].tradeOutput` | number |  |\n| `data.quotes[].estimatedDuration` | number | Estimated bridging duration in seconds |\n| `data.currencyIn` | object | Input currency info (source chain) |\n| `data.currencyOut` | object | Output currency info (destination chain) |\n| `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. |\n| `data.quotes[].bridge` | string |  |\n| `data.quotes[].tradeInput` | number |  |\n| `data.quotes[].tradeOutput` | number |  |\n| `data.quotes[].estimatedDuration` | number | Estimated bridging duration in seconds |\n| `data.quotes[].approvalTarget` | string | This bridge's deposit contract — the ERC-20 approve spender |\n| `data.quotes[].approvalRequired` | boolean | False when the existing on-chain allowance already covers the input amount |\n| `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. |\n| `data.quotes[].tx.to` | string | Target contract address |\n| `data.quotes[].tx.data` | string | Encoded calldata |\n| `data.quotes[].tx.value` | string | ETH value to send with the transaction |\n| `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `data.permissionTxns` | object[] | ERC-20 approves per bridge deposit contract; each is labeled with the bridge name — execute only the one matching the chosen quote |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"currencyIn\": {},\n    \"currencyOut\": {},\n    \"quotes\": [\n      {\n        \"bridge\": \"string\",\n        \"tradeInput\": 1.0,\n        \"tradeOutput\": 1.0,\n        \"estimatedDuration\": 1.0\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "fromChainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Source chain ID",
            "example": "1"
          },
          {
            "name": "toChainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "8453"
            },
            "description": "Destination chain ID",
            "example": "8453"
          },
          {
            "name": "tokenIn",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
            },
            "description": "Input token address on the source chain (zero address for native)",
            "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
          },
          {
            "name": "tokenOut",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
            },
            "description": "Output token address on the destination chain (zero address for native)",
            "example": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Input amount in wei",
            "example": "1000000000"
          },
          {
            "name": "slippage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 50
            },
            "description": "Slippage tolerance (basis points)",
            "example": 50
          },
          {
            "name": "account",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Account address on the source chain. Include to build transactions, omit for quote-only.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Receiver address on the destination chain (defaults to account)"
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "CHEAPEST",
                "FASTEST"
              ]
            },
            "description": "Route preference"
          },
          {
            "name": "bridges",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bridge filter (e.g. `Across,LI.FI`). Defaults to all supported bridges."
          }
        ],
        "responses": {
          "200": {
            "description": "Cross-chain swap quote or full build",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/XChainQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/XChainBuildResponse"
                        },
                        {
                          "$ref": "#/components/schemas/SpotQuoteResponse"
                        },
                        {
                          "$ref": "#/components/schemas/SpotBuildResponse"
                        }
                      ],
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "currencyIn": {},
                    "currencyOut": {},
                    "quotes": [
                      {
                        "bridge": "string",
                        "tradeInput": 1,
                        "tradeOutput": 1,
                        "estimatedDuration": 1
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "cross-chain-swap-bridge-aggregation"
      }
    },
    "/v1/actions/vaults/deposit": {
      "get": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "Vault deposit",
        "description": "The **single deposit entry point** for every share-token vault. The protocol, interface, and underlying are resolved from the `vault` (share token), so a deposit needs only `vault` + `amount` + `operator`.\n\n**What it routes, all from the share token**\n\n- **ERC-4626 family** — savings, Morpho, Fluid, Euler-Earn, Silo, Gearbox, Lagoon, Yearn. Routes directly to `vault.deposit` when no wrap/swap is needed; otherwise the 1delta Composer (wraps native ETH, handles composition).\n- **LST / liquid-staking mints** — stETH, wstETH, weETH, rETH, stCELO, pumpBTC, Solv, Core, native-staked, … Resolved from the calldata-sdk registry by `vault` and built via the protocol's mint path, including protocol-specific prep (e.g. StakedCelo validator-group selection — see `validatorGroup`).\n- **ERC-7540** async and **ERC-7575** multi-asset vaults — detected via an ERC-165 probe.\n\n`underlying` and `interface` are read on-chain (`asset()` + ERC-165) when omitted; pass them explicitly to skip the reads. For Fluid **margin vaults** (NFT-position lending markets), use `/v1/actions/lending/deposit` instead.\n\n> **Not handled here:** GMX (GM/GLV) and Hypercore vaults are USD-denominated / multi-leg, not `asset()`-based share tokens, so they keep dedicated flows — GMX via [/v1/actions/vaults/gmx](/1delta-api/vaults-gmx), Hypercore via `interface=hypercore` below. Passing one to the auto path returns `UNRESOLVED_UNDERLYING`.\n>\n> `/v1/actions/vaults/lst` and `/v1/actions/vaults/savings` remain as back-compatible aliases for their specific flows.\n\n**Execution mode** (`mode` query param, ERC-4626 path)\n\n- `auto` (default) — direct when `payAsset === underlying` and not native, otherwise composer.\n- `direct` — force direct; returns 400 when not eligible (e.g. native `payAsset`).\n- `proxy` — force the composer (legacy behavior).\n\nThe direct path is smaller (one call to the vault) and sidesteps the EVC indirection that the composer triggers. Approval target also changes: direct → the vault; proxy → the composer.\n\n**Native deposits**\n\nNative ETH is supported via the composer's wrap-then-deposit path (`mode=proxy`, or `auto` falls back automatically), and natively by most LST mints (`payAsset=0x0`). Fluid fToken vaults expose a payable `depositNative` that skips wrapping — opt in with `provider=fluid`.\n\n---\n\n## Async / multi-asset / Hypercore (`interface` query param)\n\nAuto-detected for ERC-7540/7575; only Hypercore needs an explicit `interface`:\n\n- `erc7540` — **async** vaults. Two-phase: `action=requestDeposit` (default, escrow assets) then `action=claimDeposit` (mint once fulfilled). Pass `controller` when it isn't `operator`. Track the pending request via [/v1/data/vaults/withdrawals](/1delta-api/vaults-withdrawals).\n- `erc7575` — **multi-asset** vaults (share ≠ entry token). `isShares` switches deposit-by-assets vs mint-by-shares.\n- `hypercore` — **HyperLiquid** multi-leg deposit route (explicit only). `amount` is uint64 micro-USD (USDC); `source` picks the funding origin and the response is a structured `legs[]` array (each with its own `chainId`/`async`) rather than `transactions[]`.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/vaults/deposit`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `vault` | query | string | yes | Share-token address — ERC-4626 vault or LST share token. The protocol/interface is resolved from it. (Alias: `shareToken`.) |\n| `underlying` | query | string | no | Vault's `asset()` (real ERC-20 — never the zero address). Resolved on-chain from `vault` when omitted; required only for vaults without an `asset()` getter. Not needed for LST share tokens. |\n| `amount` | query | string | yes | Amount in wei. Interpreted as assets unless `isShares=true`. |\n| `operator` | query | string | yes | User wallet executing the deposit (payer) |\n| `payAsset` | query | string | no | What the user actually pays. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer wraps before depositing). |\n| `receiver` | query | string | no | Share recipient. Defaults to `operator`. The composer mints shares directly to this address. |\n| `isShares` | query | boolean | no | When `true`, `amount` is treated as shares (mint) rather than assets (deposit). |\n| `isAll` | query | boolean | no | Full-balance deposit. Relaxes the exit-sweep tolerance so dust does not revert the tx. |\n| `provider` | query | `fluid` | no | Optional provider hint. Currently only `fluid` is recognized — it opts into Fluid's payable `depositNative` path when paying native ETH. |\n| `mode` | query | `auto`, `direct`, `proxy` | no | Execution mode. `auto` (default) routes direct when no wrap/swap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer. |\n| `interface` | query | `erc4626`, `erc7540`, `erc7575`, `hypercore`, `native-wnlp` | no | Vault interface. Auto-detected via ERC-165 when omitted (`erc4626`/`erc7540`/`erc7575`), or from the savings registry for Native `wNLP` (`native-wnlp` → `depositAndWrap`, which also fills in `underlying` — wNLP has no `asset()` to probe). Pass `hypercore` explicitly for HyperLiquid (USD multi-leg). LST share tokens are routed by registry regardless of this param. |\n| `action` | query | `requestDeposit`, `claimDeposit` | no | `interface=erc7540` only — `requestDeposit` (default) escrows assets; `claimDeposit` mints once fulfilled. |\n| `controller` | query | string | no | `interface=erc7540` controller, when not `operator`. |\n| `validatorGroup` | query | string | no | StakedCelo (stCELO) only — validator group to vote for. A `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; pass the zero address to force the default. Other LST options (`poolId`, `kind`, `referral`, …) from /vaults/lst are also accepted here. |\n| `minUsddOut` | query | string | no | sUSDD PSM zap only (`payAsset` = USDT/USDC into the sUSDD vault) — the 18-decimal USDD amount the deposit leg uses after the PSM swap. AUTO-QUOTED when omitted: the route reads the PSM’s live `tin` fee and the gem decimals and computes `amount·10^(18−dec) − fee`. Pass explicitly to pin a quote. |\n| `source` | query | `hypercore-perp`, `hypercore-spot`, `hyperevm`, `arbitrum` | no | `interface=hypercore` deposit funding origin. |\n| `hyperEvmUsdc` | query | string | no | `interface=hypercore`, `source=hyperevm` — the HyperEVM USDC token address. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "vault",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Share-token address — ERC-4626 vault or LST share token. The protocol/interface is resolved from it. (Alias: `shareToken`.)"
          },
          {
            "name": "underlying",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Vault's `asset()` (real ERC-20 — never the zero address). Resolved on-chain from `vault` when omitted; required only for vaults without an `asset()` getter. Not needed for LST share tokens."
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei. Interpreted as assets unless `isShares=true`.",
            "example": "1000000000000000000"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "User wallet executing the deposit (payer)",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "What the user actually pays. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer wraps before depositing)."
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Share recipient. Defaults to `operator`. The composer mints shares directly to this address."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When `true`, `amount` is treated as shares (mint) rather than assets (deposit)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Full-balance deposit. Relaxes the exit-sweep tolerance so dust does not revert the tx."
          },
          {
            "name": "provider",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "fluid"
              ]
            },
            "description": "Optional provider hint. Currently only `fluid` is recognized — it opts into Fluid's payable `depositNative` path when paying native ETH."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "direct",
                "proxy"
              ],
              "default": "auto"
            },
            "description": "Execution mode. `auto` (default) routes direct when no wrap/swap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer."
          },
          {
            "name": "interface",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "erc4626",
                "erc7540",
                "erc7575",
                "hypercore",
                "native-wnlp"
              ]
            },
            "description": "Vault interface. Auto-detected via ERC-165 when omitted (`erc4626`/`erc7540`/`erc7575`), or from the savings registry for Native `wNLP` (`native-wnlp` → `depositAndWrap`, which also fills in `underlying` — wNLP has no `asset()` to probe). Pass `hypercore` explicitly for HyperLiquid (USD multi-leg). LST share tokens are routed by registry regardless of this param."
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "requestDeposit",
                "claimDeposit"
              ]
            },
            "description": "`interface=erc7540` only — `requestDeposit` (default) escrows assets; `claimDeposit` mints once fulfilled."
          },
          {
            "name": "controller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "`interface=erc7540` controller, when not `operator`."
          },
          {
            "name": "validatorGroup",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "StakedCelo (stCELO) only — validator group to vote for. A `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; pass the zero address to force the default. Other LST options (`poolId`, `kind`, `referral`, …) from /vaults/lst are also accepted here."
          },
          {
            "name": "minUsddOut",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "sUSDD PSM zap only (`payAsset` = USDT/USDC into the sUSDD vault) — the 18-decimal USDD amount the deposit leg uses after the PSM swap. AUTO-QUOTED when omitted: the route reads the PSM’s live `tin` fee and the gem decimals and computes `amount·10^(18−dec) − fee`. Pass explicitly to pin a quote."
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hypercore-perp",
                "hypercore-spot",
                "hyperevm",
                "arbitrum"
              ]
            },
            "description": "`interface=hypercore` deposit funding origin."
          },
          {
            "name": "hyperEvmUsdc",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "`interface=hypercore`, `source=hyperevm` — the HyperEVM USDC token address."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata + approval(s) for the vault deposit. `interface=hypercore` returns a structured `legs[]` route instead of `transactions[]`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "vault-deposit"
      }
    },
    "/v1/actions/vaults/withdraw": {
      "get": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "Vault withdraw",
        "description": "Build calldata for an ERC-4626 vault withdraw. When the user wants the underlying back (no native unwrap), the dispatcher calls `vault.withdraw` / `vault.redeem` directly with no approval needed. When the receiver wants native ETH, falls back to the composer (unwraps WETH).\n\nThis endpoint targets **passive ERC-4626 vaults**. For Fluid's NFT-position margin vaults use `/v1/actions/lending/withdraw`.\n\n**Execution mode** (`mode` query param)\n\n- `auto` (default) — direct when `receiveAsset === underlying` and not native, otherwise composer.\n- `direct` — force direct; returns 400 when not eligible.\n- `proxy` — force the composer (legacy behavior).\n\nDirect withdraw skips the share-token approval entirely — the user calls `vault.withdraw(assets, receiver, owner=operator)` themselves and the vault uses its own balance check (`msg.sender == owner`).\n\n**Assets vs shares**\n\n- `isShares=false` (default): `amount` is assets — issues `vault.withdraw(assets, receiver, owner)`.\n- `isShares=true`: `amount` is shares — issues `vault.redeem(shares, receiver, owner)`.\n\n**Withdraw all** (`isAll=true`)\n\nTwo ways to drive a full-balance withdraw — both resolve the operator's vault-share balance and encode `vault.redeem(shares, …)`. They differ only in **where the share balance is read**:\n\n- **GET** + `isAll=true` — worker reads `balanceOf(vault, operator)` against its own configured RPC. Simple but only works when the worker can see the state (i.e. live mainnet, not fork). Returns `BALANCE_READ_FAILED` on RPC failure.\n- **POST** + `isAll=true` + body `{ \"sharesRaw\": \"<uint string>\" }` — caller pre-reads the balance against any RPC (fork, custom, premium) and supplies it. The worker just trusts and encodes. Mirrors the lending simulation pattern (`SimulationBody`).\n\nThe POST body's `amount` query param is ignored when `isAll=true`.\n\n---\n\n## Non-4626 interfaces (`interface` query param)\n\nDefault `erc4626` is the composer/direct path above. Otherwise:\n\n- `erc7540` — **async** redeem. `action=requestRedeem` (default) burns shares into the queue; `claimRedeem` / `claimWithdraw` settle once fulfilled. `controller` when not `operator`.\n- `erc7575` — **multi-asset**. Requires `share` (the share-token address); `isShares` toggles assets-out vs shares-in.\n- `hypercore` — **HyperLiquid** multi-leg withdraw route. `amount` is uint64 micro-USD; `destination` picks where the funds land. Returns a structured `legs[]` array. (Withdrawing out to Arbitrum is an L1 signed action, not EVM calldata — not offered here.)\n\n> Savings cooldowns (sUSDe) use [/v1/actions/vaults/savings](/1delta-api/vaults-savings); LST exits use [/v1/actions/vaults/lst](/1delta-api/vaults-lst).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/vaults/withdraw`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `vault` | query | string | yes | ERC-4626 share-token address |\n| `underlying` | query | string | yes | Vault's `asset()` |\n| `amount` | query | string | yes | Amount in wei. Interpreted as assets unless `isShares=true`. |\n| `operator` | query | string | yes | User wallet executing the withdraw (share holder) |\n| `receiveAsset` | query | string | no | What the user receives. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer unwraps before forwarding). |\n| `receiver` | query | string | no | Final recipient of the withdrawn assets. Defaults to `operator`. |\n| `isShares` | query | boolean | no | When `true`, `amount` is treated as shares (the composer calls `vault.redeem`). |\n| `isAll` | query | boolean | no | Full-balance withdraw. Relaxes the sweep tolerance so dust does not revert the tx. |\n| `mode` | query | `auto`, `direct`, `proxy` | no | Execution mode. `auto` (default) routes direct when no unwrap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer. |\n| `interface` | query | `erc4626`, `erc7540`, `erc7575`, `hypercore`, `native-wnlp` | no | Vault interface. `erc4626` (default) = composer/direct path. Others dispatch to dedicated builders (see description). Native `wNLP` is auto-detected from the savings registry, which also fills in `underlying`. |\n| `instant` | query | boolean | no | `interface=native-wnlp` only — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (100 bps by default), deducted from the underlying paid out rather than charged separately, and is capped by its reported `liquidity`. The default is the free queued leg: a fee is never charged unless asked for. |\n| `action` | query | `requestRedeem`, `claimRedeem`, `claimWithdraw` | no | `interface=erc7540` only — `requestRedeem` (default), `claimRedeem`, or `claimWithdraw`. `interface=native-wnlp` — `requestWithdraw` (default), `claim`, or `cancel`. |\n| `controller` | query | string | no | `interface=erc7540` controller, when not `operator`. |\n| `share` | query | string | no | `interface=erc7575` — the share-token address (required for that interface). |\n| `destination` | query | `hypercore-perp`, `hypercore-spot`, `hyperevm` | no | `interface=hypercore` withdraw destination. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "vault",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ERC-4626 share-token address"
          },
          {
            "name": "underlying",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Vault's `asset()`"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Amount in wei. Interpreted as assets unless `isShares=true`.",
            "example": "1000000000000000000"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "User wallet executing the withdraw (share holder)",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "What the user receives. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer unwraps before forwarding)."
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Final recipient of the withdrawn assets. Defaults to `operator`."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When `true`, `amount` is treated as shares (the composer calls `vault.redeem`)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Full-balance withdraw. Relaxes the sweep tolerance so dust does not revert the tx."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "direct",
                "proxy"
              ],
              "default": "auto"
            },
            "description": "Execution mode. `auto` (default) routes direct when no unwrap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer."
          },
          {
            "name": "interface",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "erc4626",
                "erc7540",
                "erc7575",
                "hypercore",
                "native-wnlp"
              ],
              "default": "erc4626"
            },
            "description": "Vault interface. `erc4626` (default) = composer/direct path. Others dispatch to dedicated builders (see description). Native `wNLP` is auto-detected from the savings registry, which also fills in `underlying`."
          },
          {
            "name": "instant",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "`interface=native-wnlp` only — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (100 bps by default), deducted from the underlying paid out rather than charged separately, and is capped by its reported `liquidity`. The default is the free queued leg: a fee is never charged unless asked for."
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "requestRedeem",
                "claimRedeem",
                "claimWithdraw"
              ]
            },
            "description": "`interface=erc7540` only — `requestRedeem` (default), `claimRedeem`, or `claimWithdraw`. `interface=native-wnlp` — `requestWithdraw` (default), `claim`, or `cancel`."
          },
          {
            "name": "controller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "`interface=erc7540` controller, when not `operator`."
          },
          {
            "name": "share",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "`interface=erc7575` — the share-token address (required for that interface)."
          },
          {
            "name": "destination",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hypercore-perp",
                "hypercore-spot",
                "hyperevm"
              ]
            },
            "description": "`interface=hypercore` withdraw destination."
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction calldata + any approval(s) needed for the vault withdraw. `interface=hypercore` returns a structured `legs[]` route instead of `transactions[]`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "vault-withdraw"
      },
      "post": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "Vault withdraw (with caller-supplied share balance)",
        "description": "POST variant for `isAll=true` when the worker can't read the operator's share balance against its own RPC — fork tests, custom RPCs, sandbox endpoints. Same query params as GET; the body supplies the balance.\n\nWhen `isAll=true` the worker treats the body's `sharesRaw` as the truth and encodes `vault.redeem(sharesRaw, receiver, operator)`. The query `amount` is ignored on this path.\n\nWhen `isAll` is omitted/false the body is ignored (caller's `amount` is authoritative) — POST and GET behave identically.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/vaults/withdraw`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `vault` | query | string | yes | ERC-4626 share-token address |\n| `underlying` | query | string | yes | Vault's `asset()` |\n| `amount` | query | string | yes | Ignored when `isAll=true` is set. Otherwise: amount in wei (assets unless `isShares=true`). |\n| `operator` | query | string | yes | User wallet (share holder) |\n| `receiveAsset` | query | string | no | Underlying token to receive. Defaults to `underlying`. |\n| `receiver` | query | string | no | Final recipient. Defaults to `operator`. |\n| `isShares` | query | boolean | no | When `true`, `amount` is shares (ignored if `isAll=true`). |\n| `isAll` | query | boolean | no | Full-balance withdraw. Body must include `sharesRaw`. |\n| `mode` | query | `auto`, `direct`, `proxy` | no | Same as GET — execution mode selector. |\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `sharesRaw` | string | yes | Operator's current vault-share balance as a decimal uint string. The worker uses this directly as the redeem amount. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "vault",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ERC-4626 share-token address"
          },
          {
            "name": "underlying",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Vault's `asset()`"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0"
            },
            "description": "Ignored when `isAll=true` is set. Otherwise: amount in wei (assets unless `isShares=true`).",
            "example": "0"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "User wallet (share holder)"
          },
          {
            "name": "receiveAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Underlying token to receive. Defaults to `underlying`."
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Final recipient. Defaults to `operator`."
          },
          {
            "name": "isShares",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "When `true`, `amount` is shares (ignored if `isAll=true`)."
          },
          {
            "name": "isAll",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Full-balance withdraw. Body must include `sharesRaw`."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "direct",
                "proxy"
              ],
              "default": "auto"
            },
            "description": "Same as GET — execution mode selector."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Caller-supplied state for `isAll=true`.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sharesRaw"
                ],
                "properties": {
                  "sharesRaw": {
                    "type": "string",
                    "pattern": "^\\d+$",
                    "description": "Operator's current vault-share balance as a decimal uint string. The worker uses this directly as the redeem amount.",
                    "example": "993566017"
                  }
                }
              },
              "example": {
                "sharesRaw": "993566017"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transaction calldata + any approval(s) needed for the vault withdraw",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "vault-withdraw-with-caller-supplied-share-balance"
      }
    },
    "/v1/actions/vaults/lst": {
      "get": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "LST / LRT mint · withdraw-request · claim · cancel",
        "operationId": "vaultsLst",
        "description": "Build calldata for **LST / LRT** (and Lagoon) actions — mint, withdraw-request, claim, and cancel — via the unified LST dispatchers. The protocol is resolved from the calldata-sdk registry by `(chainId, shareToken)`, or forced with `kind=` (required for Lagoon — `kind=lagoon&mode=sync|async` — and any unregistered vault).\n\n> **Deposits also work through the unified /v1/actions/vaults/deposit** — pass the LST share token as `vault` and it routes here automatically (no need to know it's an LST). This endpoint stays as the explicit LST route and is the home for the **exit-side** actions (`request-withdraw` / `claim` / `cancel`), which the generic deposit endpoint does not cover.\n\n---\n\n## How an integrator knows what to pay with (`acceptedInputs`)\n\nLSTs are **not** uniform ERC-4626 vaults — each protocol accepts a different set of pay assets (native ETH, an unwrapped sibling like stETH/eETH, or specific ERC-20s) and some paths require extra slippage/intermediate options. Rather than hard-coding this, **fetch the vault data first and let it drive the request**:\n\n1. `GET /v1/data/vaults?chainId=…&providers=lst` → each LST carries a `providerMeta` block:\n   - `isMintable` — `false` ⇒ no on-chain mint (e.g. cbETH); don't call this endpoint.\n   - `mintContract` — the deposit target.\n   - `exchangeRate` / `convertToShares` — to compute expected output and a `minOut`.\n   - **`acceptedInputs[]`** — the machine-readable accept-set (see below).\n2. Pick the `acceptedInputs` entry whose `asset` matches what the user holds.\n3. Call this endpoint with `action=deposit`, `payAsset=<that asset>`, and the entry's `needs[]` supplied as query params.\n\n### `acceptedInputs[]` entry shape\n\n| field | meaning |\n|---|---|\n| `asset` | `\"native\"` (pay with the chain coin → pass `payAsset=0x000…000`) or a lowercased ERC-20 address to pass as `payAsset`. |\n| `symbol` | optional UI hint (e.g. `stETH`). |\n| `mode` | `direct` (single call) · `wrap` (approve + wrap a base LST the user already holds) · `submit-wrap` (native → base → wrapped; needs the realised base amount). |\n| `needs` | option keys the caller **must** pass for this path (e.g. `[\"minMETHAmount\"]`, `[\"eEthAmount\"]`, `[\"stEthAmount\"]`). Absent ⇒ none. |\n\n**Example** — wstETH advertises three paths:\n```json\n\"acceptedInputs\": [\n  { \"asset\": \"native\", \"mode\": \"direct\" },\n  { \"asset\": \"0xae7ab9…\", \"symbol\": \"stETH\", \"mode\": \"wrap\" },\n  { \"asset\": \"native\", \"mode\": \"submit-wrap\", \"needs\": [\"stEthAmount\"] }\n]\n```\n- Pay with ETH → `payAsset=0x000…000` (one-step `receive()`).\n- Pay with stETH you already hold → `payAsset=0xae7ab9…` (approve + wrap).\n\n---\n\n## Multi-step results\n\n`wrap` / `submit-wrap` paths produce **multiple ordered transactions**. The response's `actions.transactions[]` is the sequence to execute **in order**, and `actions.permissions[]` carries any ERC-20 approvals to run **first**. Single-step mints return one transaction and (for native) no permissions. Always iterate `transactions[]`; never assume a single tx.\n\n---\n\n## Slippage / required options\n\nPaths whose `needs` includes a min-out (`minMETHAmount`, `minRSETHAmountExpected`, …) require the caller to compute the floor from the data's `exchangeRate` and pass it. Native one-step mints (stETH, ETHx, ezETH, ynETH, pufETH, wstETH-receive) need nothing beyond `amount`.\n\n---\n\n## Actions\n\n- `deposit` — mint. `amount` required; `payAsset` (default native); path options per `acceptedInputs[].needs`.\n- `request-withdraw` — start an exit (queue/cooldown). `amount` required; `inputAsset?`, `outputAsset?`, `owner?`.\n- `claim` — settle a matured exit. Identifier params: `requestIds`/`hints`/`amounts` (CSV), `tokenId`, `id`, `shares`, `assets`, `controller`, `user`, `recipient`.\n- `cancel` — cancel a pending request (same identifier params).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/vaults/lst`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `action` | query | `deposit`, `request-withdraw`, `claim`, `cancel` | no | Operation to build. |\n| `shareToken` | query | string | yes | LST share-token address (the token the user wants to mint / exit). |\n| `operator` | query | string | yes | User wallet executing the action (payer). `receiver` defaults to it. |\n| `receiver` | query | string | no | Recipient of the minted shares / claimed assets. Defaults to `operator`. |\n| `amount` | query | string | no | Required for `deposit` and `request-withdraw`. Wei, in the `payAsset` decimals. |\n| `payAsset` | query | string | no | deposit: what the user pays. Zero address (or `0xEEEE…`) = native; otherwise an ERC-20 from the LST's `acceptedInputs[].asset`. Defaults to native. |\n| `kind` | query | string | no | Protocol override — required for Lagoon (`lagoon`) and any vault not in the static registry. Otherwise resolved from `(chainId, shareToken)`. |\n| `mode` | query | `sync`, `async` | no | Lagoon deposit mode. |\n| `minOut` | query | integer | no | Generic slippage floor (wei) where the protocol path accepts one. For protocol-specific names see the LST `acceptedInputs[].needs`. |\n| `referral` | query | string | no | Optional referral address (protocols that support it). |\n| `stEthAmount` | query | integer | no | wstETH `submit-wrap` path: the realised stETH amount (read `stETH.balanceOf` after the submit leg). |\n| `eEthAmount` | query | integer | no | weETH `submit-wrap` path: the realised eETH amount (read after the deposit leg). |\n| `vault` | query | string | no | StakeWise per-vault target (and other per-vault protocols). |\n| `poolId` | query | string | no | Solv pool selector. |\n| `validatorGroup` | query | string | no | StakedCelo (stCELO) deposit: validator group to vote for — a `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; zero address forces the default. |\n| `rewardVault` | query | string | no | BeraPaw reward-vault target. |\n| `stakingToken` | query | string | no | Bearn staking-token target. |\n| `inputAsset` | query | string | no | request-withdraw: asset being burned, when the protocol needs it disambiguated. |\n| `outputAsset` | query | string | no | request-withdraw / claim: desired exit asset, when the protocol supports a choice. |\n| `owner` | query | string | no | request-withdraw: position owner, when not `operator`. |\n| `requestIds` | query | string | no | claim/cancel: CSV of withdrawal-request ids. |\n| `hints` | query | string | no | claim/cancel: CSV of finalization hints (Lido). |\n| `amounts` | query | string | no | claim/cancel: CSV of per-request amounts. |\n| `tokenId` | query | integer | no | claim/cancel: NFT request id. |\n| `id` | query | integer | no | claim/cancel: numeric request id. |\n| `shares` | query | integer | no | claim: share amount (7540/4626 savings). |\n| `assets` | query | integer | no | claim: asset amount. |\n| `controller` | query | string | no | claim: 7540 controller, when not `receiver`. |\n| `user` | query | string | no | claim/cancel: position user, when not `operator`. |\n| `recipient` | query | string | no | claim: payout recipient, when supported. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "deposit",
                "request-withdraw",
                "claim",
                "cancel"
              ],
              "default": "deposit"
            },
            "description": "Operation to build."
          },
          {
            "name": "shareToken",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"
            },
            "description": "LST share-token address (the token the user wants to mint / exit).",
            "example": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "User wallet executing the action (payer). `receiver` defaults to it.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the minted shares / claimed assets. Defaults to `operator`."
          },
          {
            "name": "amount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "Required for `deposit` and `request-withdraw`. Wei, in the `payAsset` decimals.",
            "example": "1000000000000000000"
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "deposit: what the user pays. Zero address (or `0xEEEE…`) = native; otherwise an ERC-20 from the LST's `acceptedInputs[].asset`. Defaults to native."
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Protocol override — required for Lagoon (`lagoon`) and any vault not in the static registry. Otherwise resolved from `(chainId, shareToken)`."
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sync",
                "async"
              ]
            },
            "description": "Lagoon deposit mode."
          },
          {
            "name": "minOut",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Generic slippage floor (wei) where the protocol path accepts one. For protocol-specific names see the LST `acceptedInputs[].needs`."
          },
          {
            "name": "referral",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional referral address (protocols that support it)."
          },
          {
            "name": "stEthAmount",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "wstETH `submit-wrap` path: the realised stETH amount (read `stETH.balanceOf` after the submit leg)."
          },
          {
            "name": "eEthAmount",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "weETH `submit-wrap` path: the realised eETH amount (read after the deposit leg)."
          },
          {
            "name": "vault",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "StakeWise per-vault target (and other per-vault protocols)."
          },
          {
            "name": "poolId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Solv pool selector."
          },
          {
            "name": "validatorGroup",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "StakedCelo (stCELO) deposit: validator group to vote for — a `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; zero address forces the default."
          },
          {
            "name": "rewardVault",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "BeraPaw reward-vault target."
          },
          {
            "name": "stakingToken",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Bearn staking-token target."
          },
          {
            "name": "inputAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "request-withdraw: asset being burned, when the protocol needs it disambiguated."
          },
          {
            "name": "outputAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "request-withdraw / claim: desired exit asset, when the protocol supports a choice."
          },
          {
            "name": "owner",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "request-withdraw: position owner, when not `operator`."
          },
          {
            "name": "requestIds",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim/cancel: CSV of withdrawal-request ids."
          },
          {
            "name": "hints",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim/cancel: CSV of finalization hints (Lido)."
          },
          {
            "name": "amounts",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim/cancel: CSV of per-request amounts."
          },
          {
            "name": "tokenId",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "claim/cancel: NFT request id."
          },
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "claim/cancel: numeric request id."
          },
          {
            "name": "shares",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "claim: share amount (7540/4626 savings)."
          },
          {
            "name": "assets",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "claim: asset amount."
          },
          {
            "name": "controller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim: 7540 controller, when not `receiver`."
          },
          {
            "name": "user",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim/cancel: position user, when not `operator`."
          },
          {
            "name": "recipient",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "claim: payout recipient, when supported."
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered `transactions[]` (execute in sequence) + ERC-20 `permissions[]` (execute first). Single-step mints return one transaction.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/vaults/savings": {
      "get": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "Savings-vault request-withdraw · claim · deposit · cancel",
        "operationId": "vaultsSavings",
        "description": "Build calldata for **savings-vault** exits — the cooldown / async-redeem mechanics that plain ERC-4626 `withdraw` can't express (Ethena `sUSDe`, `erc7540` async vaults, instant `erc4626` redeem, and Native Credit Pool `wNLP`) — plus the deposit leg for the one family that isn't ERC-4626. The protocol is resolved from the calldata-sdk savings registry by `(chainId, shareToken)`, or forced with `kind=ethena|erc7540|erc4626|native-wnlp`.\n\n> **ERC-4626 savings deposits go through /v1/actions/vaults/deposit.** Native `wNLP` works on *either* route — `/vaults/deposit` auto-detects it from the registry and needs no `underlying`.\n\n## Actions\n\n- `request-withdraw` (default) — start the exit:\n  - **Ethena** → `cooldownShares(amount)` (or `cooldownAssets` when `byAssets=true`); escrows the assets for the cooldown window.\n  - **erc7540** → `requestRedeem`.\n  - **erc4626** → instant `redeem` (no cooldown).\n  - **native-wnlp** → `WithdrawQueue.requestWithdrawal(amount)` — the **free** leg; the payout is snapshotted at request time and claimable after the queue window. Pass `instant=true` for `instantRedeem` instead: one transaction, no wait, but it costs the vault's `withdrawFeeBps` (100 bps by default) — deducted from the underlying paid out, never charged as a separate transfer — and is capped by its reported `liquidity`.\n- `claim` — settle a matured exit:\n  - **Ethena** → `unstake(receiver)`.\n  - **erc7540 / erc4626** → `redeem` (pass `shares`).\n  - **native-wnlp** → `claimWithdrawalTo(receiver)`; no `shares` — the queue always pays the full request.\n- `deposit` — **native-wnlp only** (`depositAndWrap(receiver, amount)`). Every other kind is a plain ERC-4626 mint and is rejected here with a pointer to `/vaults/deposit`.\n- `cancel` — **native-wnlp only**; withdraw an open queued request and take the shares back. One request per address, so cancel is also how you resize one.\n\nTrack pending requests via [/v1/data/vaults/withdrawals](/1delta-api/vaults-withdrawals).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/vaults/savings`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. |\n| `action` | query | `request-withdraw`, `claim`, `deposit`, `cancel` | no | Operation to build. `deposit` and `cancel` are Native `wNLP` only. |\n| `shareToken` | query | string | yes | Savings share-token address (e.g. sUSDe `0x9d39a5de30e57443bff2a8307a4256c8797a3497`). |\n| `operator` | query | string | yes | User wallet executing the action (share holder). `receiver` defaults to it. |\n| `receiver` | query | string | no | Recipient of the claimed assets. Defaults to `operator`. |\n| `kind` | query | `ethena`, `erc7540`, `erc4626`, `native-wnlp` | no | Protocol override. Otherwise resolved from `(chainId, shareToken)`. |\n| `amount` | query | string | no | request-withdraw: shares to cool down (or underlying assets when `byAssets=true`). deposit: underlying to wrap. Wei. |\n| `byAssets` | query | boolean | no | request-withdraw, **Ethena only** — interpret `amount` as the underlying asset amount (`cooldownAssets`) instead of shares (`cooldownShares`). |\n| `instant` | query | boolean | no | request-withdraw, **native-wnlp only** — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (deducted from the underlying paid out) and is capped by its `liquidity`; check both on [/v1/data/vaults](/1delta-api/vaults) first. |\n| `underlying` | query | string | no | deposit, **native-wnlp only** — the asset to wrap, when the pool is too new to be in the registry. Otherwise resolved automatically. |\n| `shares` | query | integer | no | claim: share amount to redeem (erc7540 / erc4626). |\n| `owner` | query | string | no | request-withdraw: share owner, when not `operator` (erc4626 redeem). |\n| `controller` | query | string | no | erc7540 controller, when not `operator`. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "request-withdraw",
                "claim",
                "deposit",
                "cancel"
              ],
              "default": "request-withdraw"
            },
            "description": "Operation to build. `deposit` and `cancel` are Native `wNLP` only."
          },
          {
            "name": "shareToken",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0x9d39a5de30e57443bff2a8307a4256c8797a3497"
            },
            "description": "Savings share-token address (e.g. sUSDe `0x9d39a5de30e57443bff2a8307a4256c8797a3497`).",
            "example": "0x9d39a5de30e57443bff2a8307a4256c8797a3497"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "User wallet executing the action (share holder). `receiver` defaults to it.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient of the claimed assets. Defaults to `operator`."
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ethena",
                "erc7540",
                "erc4626",
                "native-wnlp"
              ]
            },
            "description": "Protocol override. Otherwise resolved from `(chainId, shareToken)`."
          },
          {
            "name": "amount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "request-withdraw: shares to cool down (or underlying assets when `byAssets=true`). deposit: underlying to wrap. Wei.",
            "example": "1000000000000000000"
          },
          {
            "name": "byAssets",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "request-withdraw, **Ethena only** — interpret `amount` as the underlying asset amount (`cooldownAssets`) instead of shares (`cooldownShares`)."
          },
          {
            "name": "instant",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "request-withdraw, **native-wnlp only** — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (deducted from the underlying paid out) and is capped by its `liquidity`; check both on [/v1/data/vaults](/1delta-api/vaults) first."
          },
          {
            "name": "underlying",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "deposit, **native-wnlp only** — the asset to wrap, when the pool is too new to be in the registry. Otherwise resolved automatically."
          },
          {
            "name": "shares",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "claim: share amount to redeem (erc7540 / erc4626)."
          },
          {
            "name": "owner",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "request-withdraw: share owner, when not `operator` (erc4626 redeem)."
          },
          {
            "name": "controller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "erc7540 controller, when not `operator`."
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered `transactions[]` + ERC-20 `permissions[]` (run first). Each step carries its builder label as `description`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/vaults/gmx": {
      "get": {
        "tags": [
          "Vaults (Actions)"
        ],
        "summary": "GMX V2 GM / GLV deposit · withdraw · cancel",
        "operationId": "vaultsGmx",
        "description": "Build calldata for **GMX V2** GM-market / GLV liquidity actions (Arbitrum `42161`, Avalanche `43114`). These are **async**: each call returns a single `ExchangeRouter` (GM) / `GlvRouter` (GLV) `multicall` transaction (plus any ERC-20 approval to the GMX Router), and a **keeper** executes the request a few seconds later. The deposit/withdraw tx must carry a native `executionFee` (the keeper's gas reimbursement) — GMX reverts if it's underpaid.\n\n## Actions\n\n- `deposit` (default) — add liquidity. Needs `longToken` + `shortToken` (the market legs), `payAsset` (the token paid in), `amount`, `executionFee`.\n- `withdraw` — remove liquidity (burn GM/GLV tokens). Needs `amount` (GM/GLV tokens), `executionFee`.\n- `cancel` — cancel a still-pending deposit/withdrawal ticket. Needs `request=deposit|withdrawal` and the 32-byte `key` (from [/v1/data/vaults/gmx](/1delta-api/vaults-gmx)).\n\n## GM vs GLV (`kind`)\n\n- `gm` (default) — a single GM market; `market` defaults to `vault`.\n- `glv` — an auto-rebalancing GLV vault; you **must** name the GM `market` within the GLV.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/vaults/gmx`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID — `42161` (Arbitrum) or `43114` (Avalanche). See the `ChainId` schema for the full set of supported chains. |\n| `action` | query | `deposit`, `withdraw`, `cancel` | no | Operation to build. |\n| `kind` | query | `gm`, `glv` | no | Pool kind. |\n| `vault` | query | string | yes | GM market token (`gm`) or GLV token (`glv`). |\n| `operator` | query | string | yes | Caller wallet (deposit/withdraw). `receiver` defaults to it. |\n| `receiver` | query | string | no | Recipient. Defaults to `operator`. |\n| `amount` | query | string | no | deposit: input-token amount. withdraw: GM/GLV tokens to burn. Wei. |\n| `executionFee` | query | string | no | deposit/withdraw: native keeper fee (wei), forwarded as the tx `value`. GMX rejects underpaid requests — quote it from the GMX UI/SDK. |\n| `market` | query | string | no | GLV: **required** — the GM market within the GLV. GM: defaults to `vault`. |\n| `longToken` | query | string | no | deposit: **required** — the market long leg. |\n| `shortToken` | query | string | no | deposit: **required** — the market short leg. |\n| `payAsset` | query | string | no | deposit: token paid in. Zero / `0xEEEE…` = native. Defaults to `longToken`. |\n| `minOut` | query | integer | no | Slippage floor on output GM/GLV (deposit) or output token (withdraw). |\n| `minLongTokenAmount` | query | integer | no | withdraw: min long-token received. |\n| `minShortTokenAmount` | query | integer | no | withdraw: min short-token received. |\n| `isMarketTokenDeposit` | query | boolean | no | deposit: the input is already GM tokens (GLV deposit of an existing GM position). |\n| `shouldUnwrapNativeToken` | query | boolean | no | withdraw: unwrap WETH/WAVAX output to native. |\n| `uiFeeReceiver` | query | string | no | Optional UI-fee recipient. |\n| `callbackGasLimit` | query | integer | no | Optional gas limit for the keeper callback. |\n| `request` | query | `deposit`, `withdrawal` | no | cancel: which pending ticket to cancel. |\n| `key` | query | string | no | cancel: 32-byte request key (from `/v1/data/vaults/gmx`). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "42161"
            },
            "description": "Chain ID — `42161` (Arbitrum) or `43114` (Avalanche). See the `ChainId` schema for the full set of supported chains.",
            "example": "42161"
          },
          {
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "deposit",
                "withdraw",
                "cancel"
              ],
              "default": "deposit"
            },
            "description": "Operation to build."
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "gm",
                "glv"
              ],
              "default": "gm"
            },
            "description": "Pool kind."
          },
          {
            "name": "vault",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "GM market token (`gm`) or GLV token (`glv`)."
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            },
            "description": "Caller wallet (deposit/withdraw). `receiver` defaults to it.",
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "receiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Recipient. Defaults to `operator`."
          },
          {
            "name": "amount",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "1000000000000000000"
            },
            "description": "deposit: input-token amount. withdraw: GM/GLV tokens to burn. Wei.",
            "example": "1000000000000000000"
          },
          {
            "name": "executionFee",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "75000000000000"
            },
            "description": "deposit/withdraw: native keeper fee (wei), forwarded as the tx `value`. GMX rejects underpaid requests — quote it from the GMX UI/SDK.",
            "example": "75000000000000"
          },
          {
            "name": "market",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "GLV: **required** — the GM market within the GLV. GM: defaults to `vault`."
          },
          {
            "name": "longToken",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "deposit: **required** — the market long leg."
          },
          {
            "name": "shortToken",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "deposit: **required** — the market short leg."
          },
          {
            "name": "payAsset",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "deposit: token paid in. Zero / `0xEEEE…` = native. Defaults to `longToken`."
          },
          {
            "name": "minOut",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Slippage floor on output GM/GLV (deposit) or output token (withdraw)."
          },
          {
            "name": "minLongTokenAmount",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "withdraw: min long-token received."
          },
          {
            "name": "minShortTokenAmount",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "withdraw: min short-token received."
          },
          {
            "name": "isMarketTokenDeposit",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "deposit: the input is already GM tokens (GLV deposit of an existing GM position)."
          },
          {
            "name": "shouldUnwrapNativeToken",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "withdraw: unwrap WETH/WAVAX output to native."
          },
          {
            "name": "uiFeeReceiver",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional UI-fee recipient."
          },
          {
            "name": "callbackGasLimit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Optional gas limit for the keeper callback."
          },
          {
            "name": "request",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "deposit",
                "withdrawal"
              ]
            },
            "description": "cancel: which pending ticket to cancel."
          },
          {
            "name": "key",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "cancel: 32-byte request key (from `/v1/data/vaults/gmx`)."
          }
        ],
        "responses": {
          "200": {
            "description": "A single `ExchangeRouter`/`GlvRouter` `multicall` transaction (plus any Router approval). A keeper executes the request shortly after.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/midnight/make": {
      "get": {
        "tags": [
          "Midnight"
        ],
        "summary": "Make offer (build typed-data)",
        "operationId": "midnight-make",
        "description": "**MAKE — step 1 of 2.** Build the EIP-712 typed-data for a limit offer at your own rate.\n\n**Morpho Midnight is an order-book lender** — liquidity is a book of maker offers, not a pool — so there are two ways to interact:\n\n- **TAKE** (fill existing offers): use the **standard lending actions**, which route to Midnight automatically for a `MORPHO_MIDNIGHT_<id>` market. There is no separate \"take\" endpoint.\n  - **lend** → [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) — fills the **ask** side (supply offers)\n  - **borrow** → [`/v1/actions/lending/borrow`](/1delta-api/lending-borrow) — fills the **bid** side (demand offers)\n  - **repay** / **withdraw** → [`/v1/actions/lending/repay`](/1delta-api/lending-repay) · [`/withdraw`](/1delta-api/lending-withdraw)\n  - Read the live two-sided ladder from [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest) — each order-book market's loan leg carries `offers` (bids) and `lendOffers` (asks), best-first, with per-level `aprPct`, `assets`, and `cumulativeAssets`.\n- **MAKE** (post your own limit offer at a chosen rate): the endpoints in this section (`/v1/actions/midnight/*`) plus [`/v1/data/lending/orders`](/1delta-api/lending-orders) to list and cancel them.\n\n**Make flow (worker-assisted signing):**\n1. `GET /v1/actions/midnight/make` → returns `typedData`, the echoed `inputs`, and a one-time `authorization` tx.\n2. The maker signs `typedData` with their wallet (`wallet.signTypedData`).\n3. `POST /v1/actions/midnight/finalize` with `{ inputs, signature }` → the on-chain transaction that publishes the offer to the Midnight mempool.\n\nIf `authorization` is present and the maker has **not** yet authorized the ratifier (read `isAuthorized` on-chain), send that one-time `setIsAuthorized` transaction **before** finalizing. The APR you request is snapped to an order-book tick — `aprPctSnapped` is the exact rate the offer will quote.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/midnight/make`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). Midnight is Base-only today. See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | `MORPHO_MIDNIGHT_<id>` lender key (the market to post into). See the `LenderId` schema for the full set of accepted values. |\n| `side` | query | `lend`, `borrow` | yes | `lend` posts a bid (you lend when taken); `borrow` posts an ask (you borrow when taken). |\n| `aprPct` | query | number | yes | Your target APR in percent (alias: `rate`). Snapped to an order-book tick; see `aprPctSnapped` in the response. |\n| `size` | query | string | yes | Offer size in loan-token units (integer wei). |\n| `expiry` | query | integer | yes | Offer expiry, unix seconds. Must be in the future and ≤ the market maturity. |\n| `account` | query | string | yes | Maker (offer owner) address. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Everything the frontend needs to sign and publish a maker offer (step 1 of the make flow). `actions` is `null` — the publish transaction is produced by `/finalize` after signing. |\n| `data.typedData` | object | EIP-712 typed-data to sign with `wallet.signTypedData` (bigints serialized as strings — sign the response as-is). |\n| `data.inputs` | object | Deterministic offer inputs. Returned verbatim by `GET /v1/actions/midnight/make`; POST them back **unchanged** to `/v1/actions/midnight/finalize` alongside the signature so the worker rebuilds the identical offer tree. Any tampering fails on-chain ratification. |\n| `data.inputs.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `data.inputs.lender` | string | `MORPHO_MIDNIGHT_<id>` lender key. |\n| `data.inputs.buy` | boolean | `true` = maker BUYS units (a **lend** offer / bid); `false` = maker SELLS units (a **borrow** offer / ask). |\n| `data.inputs.tick` | string | Order-book tick the APR snapped to. |\n| `data.inputs.start` | string |  |\n| `data.inputs.expiry` | string | Offer expiry, unix seconds. |\n| `data.inputs.maxAssets` | string | Maker-side size in loan-token units. |\n| `data.inputs.maker` | string | Maker (offer owner) address. |\n| `data.authorization` | object | One-time `setIsAuthorized(ecrecoverRatifier, true)` transaction on the Midnight core. Send FIRST, only if the maker has not authorized the ratifier yet (read `isAuthorized` on-chain). |\n| `data.authorization.to` | string |  |\n| `data.authorization.data` | string | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.authorization.value` | string | Native-token value to send with the transaction, in wei. |\n| `data.authorization.ratifier` | string |  |\n| `data.aprPctSnapped` | number | The exact APR (percent) after tick-snapping — what the offer will actually quote once posted. |\n| `data.maturity` | number | Market maturity, unix seconds. |\n| `actions` | null |  |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"typedData\": {},\n    \"inputs\": {\n      \"chainId\": \"8453\",\n      \"lender\": \"MORPHO_MIDNIGHT_0xABC\\u2026\",\n      \"buy\": true,\n      \"tick\": \"string\",\n      \"start\": \"0\",\n      \"expiry\": \"string\",\n      \"maxAssets\": \"string\",\n      \"maker\": \"string\"\n    },\n    \"authorization\": {\n      \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n      \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n      \"value\": \"1000000000000000000\",\n      \"ratifier\": \"string\"\n    },\n    \"aprPctSnapped\": 3.49,\n    \"maturity\": 1.0\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "8453"
            },
            "description": "Chain ID (alias: `chain`). Midnight is Base-only today. See the `ChainId` schema for the full set of supported chains.",
            "example": "8453"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "MORPHO_MIDNIGHT_0xABC…"
            },
            "description": "`MORPHO_MIDNIGHT_<id>` lender key (the market to post into). See the `LenderId` schema for the full set of accepted values.",
            "example": "MORPHO_MIDNIGHT_0xABC…"
          },
          {
            "name": "side",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "lend",
                "borrow"
              ]
            },
            "description": "`lend` posts a bid (you lend when taken); `borrow` posts an ask (you borrow when taken)."
          },
          {
            "name": "aprPct",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "example": 3.49
            },
            "description": "Your target APR in percent (alias: `rate`). Snapped to an order-book tick; see `aprPctSnapped` in the response.",
            "example": 3.49
          },
          {
            "name": "size",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Offer size in loan-token units (integer wei).",
            "example": "1000000000"
          },
          {
            "name": "expiry",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "example": 1793491200
            },
            "description": "Offer expiry, unix seconds. Must be in the future and ≤ the market maturity.",
            "example": 1793491200
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Maker (offer owner) address."
          }
        ],
        "responses": {
          "200": {
            "description": "Offer typed-data, echoed inputs, and one-time authorization",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "$ref": "#/components/schemas/MidnightMakeResponse"
                    },
                    "actions": {
                      "type": "null"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "typedData": {},
                    "inputs": {
                      "chainId": "8453",
                      "lender": "MORPHO_MIDNIGHT_0xABC…",
                      "buy": true,
                      "tick": "string",
                      "start": "0",
                      "expiry": "string",
                      "maxAssets": "string",
                      "maker": "string"
                    },
                    "authorization": {
                      "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                      "data": "0x617ba037000000000000000000000000c02aaa39b2",
                      "value": "1000000000000000000",
                      "ratifier": "string"
                    },
                    "aprPctSnapped": 3.49,
                    "maturity": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/midnight/finalize": {
      "post": {
        "tags": [
          "Midnight"
        ],
        "summary": "Make offer (finalize + publish)",
        "operationId": "midnight-finalize",
        "description": "**MAKE — step 2 of 2.** Ratify the maker's signature and encode the on-chain payload that publishes the offer to the Midnight mempool (where the offer API indexes it).\n\nPOST the `inputs` returned verbatim by `/v1/actions/midnight/make` together with the maker's `signature`. The worker rebuilds the identical offer tree from `inputs` and binds the signature to it — any change to `inputs` fails ratification on-chain. Returns the single publish transaction in `actions.transactions`.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/midnight/finalize`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `inputs` | object | yes | Deterministic offer inputs. Returned verbatim by `GET /v1/actions/midnight/make`; POST them back **unchanged** to `/v1/actions/midnight/finalize` alongside the signature so the worker rebuilds the identical offer tree. Any tampering fails on-chain ratification. |\n| `inputs.chainId` | string | no | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `inputs.lender` | string | no | `MORPHO_MIDNIGHT_<id>` lender key. |\n| `inputs.buy` | boolean | no | `true` = maker BUYS units (a **lend** offer / bid); `false` = maker SELLS units (a **borrow** offer / ask). |\n| `inputs.tick` | string | no | Order-book tick the APR snapped to. |\n| `inputs.start` | string | no |  |\n| `inputs.expiry` | string | no | Offer expiry, unix seconds. |\n| `inputs.maxAssets` | string | no | Maker-side size in loan-token units. |\n| `inputs.maker` | string | no | Maker (offer owner) address. |\n| `signature` | string | yes | Maker signature over `typedData` (0x hex). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MidnightFinalizeRequest"
              },
              "example": {
                "inputs": {
                  "chainId": "8453",
                  "lender": "MORPHO_MIDNIGHT_0xABC…",
                  "buy": true,
                  "tick": "string",
                  "start": "0",
                  "expiry": "string",
                  "maxAssets": "string",
                  "maker": "string"
                },
                "signature": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mempool publish transaction (in `actions.transactions`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/midnight/cancel": {
      "get": {
        "tags": [
          "Midnight"
        ],
        "summary": "Cancel offer",
        "operationId": "midnight-cancel",
        "description": "Cancel one of the maker's open offers. Calls `cancelRoot(maker, root)` on the Midnight EcrecoverRatifier, invalidating the offer under that tree `root`. A plain on-chain transaction by the maker — no signature needed.\n\nGet the offer's `root` from [`/v1/data/lending/orders`](/1delta-api/lending-orders) (the order's `id`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/midnight/cancel`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `account` | query | string | yes | Maker (offer owner) address. |\n| `root` | query | string | yes | Offer tree root (bytes32) — the order `id` from `/v1/data/lending/orders`. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "8453"
            },
            "description": "Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "8453"
          },
          {
            "name": "account",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Maker (offer owner) address."
          },
          {
            "name": "root",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Offer tree root (bytes32) — the order `id` from `/v1/data/lending/orders`."
          }
        ],
        "responses": {
          "200": {
            "description": "The `cancelRoot` transaction (in `actions.transactions`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/offer": {
      "post": {
        "tags": [
          "Term"
        ],
        "summary": "Lock lend offers (auction)",
        "operationId": "term-offer",
        "description": "**AUCTION LEND — step 1 of 2.** Build the `lockOffers` transaction that submits sealed lend offers to the repo's active `TermAuctionOfferLocker`. Reveal them after the auction's reveal window opens via `/v1/actions/term/reveal-offers`.\n\n**Term Finance is a fixed-rate tri-party-repo lender** (NOT a Morpho Blue fork) with two lend surfaces:\n\n- **Secondary order book** (`RepoTokenLinkedList`): buy/sell repo tokens continuously. LEND (buy a repo token) routes through the **standard lending action** [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) for a `TERM_FINANCE_<id>` market. List/cancel your own repo tokens with `/v1/actions/term/list` · `/unlist`, and read your listings + auction submissions from the unified [`/v1/data/lending/orders`](/1delta-api/lending-orders).\n- **Primary auctions** (sealed-bid): submit a lend **offer** or borrow **bid**, then **reveal** it. The endpoints in this section (`/v1/actions/term/*`) build those transactions.\n\n**Servicing** (repay / redeem / collateral) always uses the standard lending actions: [repay](/1delta-api/lending-repay) · [withdraw](/1delta-api/lending-withdraw) · [deposit](/1delta-api/lending-deposit) (collateral leg).\n\n**Sealed commitments:** `offerPriceHash` / `bidPriceHash` = `keccak(price, nonce)` are computed **client-side** so the server never sees your secret price/nonce before reveal.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/term/offer`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `submissions` | object[] | yes |  |\n| `submissions[].id` | string | no | bytes32 — omit / zero for a new offer (the locker assigns it). |\n| `submissions[].offeror` | string | yes | Offer owner address. |\n| `submissions[].offerPriceHash` | string | yes | bytes32 commitment = `keccak(price, nonce)`, computed client-side; revealed later. |\n| `submissions[].amount` | string | yes | Offer size in purchase-token units (integer wei). |\n| `submissions[].purchaseToken` | string | no | Optional; defaults to the repo's purchase token. |\n| `referral` | string | no | Optional referral address. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TermOfferRequest"
              },
              "example": {
                "chainId": "1",
                "lender": "TERM_FINANCE_0xABC…",
                "submissions": [
                  {
                    "id": "string",
                    "offeror": "string",
                    "offerPriceHash": "string",
                    "amount": "1000000000000000000",
                    "purchaseToken": "string"
                  }
                ],
                "referral": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `lockOffers` transaction + purchase-token approval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/bid": {
      "post": {
        "tags": [
          "Term"
        ],
        "summary": "Lock borrow bids (auction)",
        "operationId": "term-bid",
        "description": "**AUCTION BORROW — step 1 of 2.** Build the `lockBids` transaction that submits sealed borrow bids (escrowing collateral) to the repo's active `TermAuctionBidLocker`. Reveal them via `/v1/actions/term/reveal-bids`.\n\n**Term Finance is a fixed-rate tri-party-repo lender** (NOT a Morpho Blue fork) with two lend surfaces:\n\n- **Secondary order book** (`RepoTokenLinkedList`): buy/sell repo tokens continuously. LEND (buy a repo token) routes through the **standard lending action** [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) for a `TERM_FINANCE_<id>` market. List/cancel your own repo tokens with `/v1/actions/term/list` · `/unlist`, and read your listings + auction submissions from the unified [`/v1/data/lending/orders`](/1delta-api/lending-orders).\n- **Primary auctions** (sealed-bid): submit a lend **offer** or borrow **bid**, then **reveal** it. The endpoints in this section (`/v1/actions/term/*`) build those transactions.\n\n**Servicing** (repay / redeem / collateral) always uses the standard lending actions: [repay](/1delta-api/lending-repay) · [withdraw](/1delta-api/lending-withdraw) · [deposit](/1delta-api/lending-deposit) (collateral leg).\n\n**Sealed commitments:** `offerPriceHash` / `bidPriceHash` = `keccak(price, nonce)` are computed **client-side** so the server never sees your secret price/nonce before reveal.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/term/bid`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `submissions` | object[] | yes |  |\n| `submissions[].id` | string | no | bytes32 — omit / zero for a new bid. |\n| `submissions[].bidder` | string | yes | Bid owner address. |\n| `submissions[].bidPriceHash` | string | yes | bytes32 commitment = `keccak(price, nonce)`, computed client-side. |\n| `submissions[].amount` | string | yes | Borrow size in purchase-token units (integer wei). |\n| `submissions[].collateralAmounts` | string[] | yes | Collateral amounts to escrow, aligned with `collateralTokens`. |\n| `submissions[].collateralTokens` | string[] | yes | Collateral token addresses. |\n| `submissions[].purchaseToken` | string | no | Optional; defaults to the repo's purchase token. |\n| `referral` | string | no | Optional referral address. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TermBidRequest"
              },
              "example": {
                "chainId": "1",
                "lender": "TERM_FINANCE_0xABC…",
                "submissions": [
                  {
                    "id": "string",
                    "bidder": "string",
                    "bidPriceHash": "string",
                    "amount": "1000000000000000000",
                    "collateralAmounts": [
                      "1000000000000000000"
                    ],
                    "collateralTokens": [
                      "string"
                    ],
                    "purchaseToken": "string"
                  }
                ],
                "referral": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `lockBids` transaction + per-collateral approvals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/reveal-offers": {
      "post": {
        "tags": [
          "Term"
        ],
        "summary": "Reveal locked offers",
        "operationId": "term-reveal-offers",
        "description": "**AUCTION LEND — step 2 of 2.** Reveal previously-locked offers (opens the sealed price + nonce) after the reveal window opens.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/term/reveal-offers`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `ids` | string[] | yes | bytes32 offer/bid ids. |\n| `prices` | string[] | yes | Revealed prices (integer). |\n| `nonces` | string[] | yes | Revealed nonces. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TermRevealRequest"
              },
              "example": {
                "chainId": "1",
                "lender": "TERM_FINANCE_0xABC…",
                "ids": [
                  "string"
                ],
                "prices": [
                  "string"
                ],
                "nonces": [
                  "string"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `revealOffers` transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/reveal-bids": {
      "post": {
        "tags": [
          "Term"
        ],
        "summary": "Reveal locked bids",
        "operationId": "term-reveal-bids",
        "description": "**AUCTION BORROW — step 2 of 2.** Reveal previously-locked bids after the reveal window opens.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/term/reveal-bids`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `ids` | string[] | yes | bytes32 offer/bid ids. |\n| `prices` | string[] | yes | Revealed prices (integer). |\n| `nonces` | string[] | yes | Revealed nonces. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TermRevealRequest"
              },
              "example": {
                "chainId": "1",
                "lender": "TERM_FINANCE_0xABC…",
                "ids": [
                  "string"
                ],
                "prices": [
                  "string"
                ],
                "nonces": [
                  "string"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The `revealBids` transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/unlock-offers": {
      "get": {
        "tags": [
          "Term"
        ],
        "summary": "Unlock (cancel) offers",
        "operationId": "term-unlock-offers",
        "description": "Cancel unrevealed offers, reclaiming the escrowed purchase token.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/term/unlock-offers`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | `TERM_FINANCE_<id>` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values. |\n| `ids` | query | string | yes | Comma-separated bytes32 offer/bid ids to unlock. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…"
            },
            "description": "`TERM_FINANCE_<id>` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values.",
            "example": "TERM_FINANCE_0xABC…"
          },
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bytes32 offer/bid ids to unlock."
          }
        ],
        "responses": {
          "200": {
            "description": "The `unlockOffers` transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/unlock-bids": {
      "get": {
        "tags": [
          "Term"
        ],
        "summary": "Unlock (cancel) bids",
        "operationId": "term-unlock-bids",
        "description": "Cancel unrevealed bids, reclaiming escrowed collateral.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/term/unlock-bids`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | `TERM_FINANCE_<id>` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values. |\n| `ids` | query | string | yes | Comma-separated bytes32 offer/bid ids to unlock. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…"
            },
            "description": "`TERM_FINANCE_<id>` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values.",
            "example": "TERM_FINANCE_0xABC…"
          },
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bytes32 offer/bid ids to unlock."
          }
        ],
        "responses": {
          "200": {
            "description": "The `unlockBids` transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/list": {
      "get": {
        "tags": [
          "Term"
        ],
        "summary": "Create a secondary listing",
        "operationId": "term-list",
        "description": "List repo tokens for sale on the secondary `RepoTokenLinkedList` order book (early exit). Escrows the repo token, so the response includes a repo-token approval.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/term/list`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | `TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values. |\n| `amount` | query | string | yes | Amount to list, repo-token units (integer wei). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…"
            },
            "description": "`TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values.",
            "example": "TERM_FINANCE_0xABC…"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1000000000"
            },
            "description": "Amount to list, repo-token units (integer wei).",
            "example": "1000000000"
          }
        ],
        "responses": {
          "200": {
            "description": "The `createListing` transaction + repo-token approval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/term/unlist": {
      "get": {
        "tags": [
          "Term"
        ],
        "summary": "Cancel a secondary listing",
        "operationId": "term-unlist",
        "description": "Cancel one of your secondary-market listings by `listingId` (the order `id` from [`/v1/data/lending/orders`](/1delta-api/lending-orders)).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/term/unlist`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | `TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values. |\n| `listingId` | query | string | yes | The listing id to cancel. |\n| `skipRedeem` | query | boolean | no | Skip auto-redeem of the returned repo token (default false). |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1"
            },
            "description": "Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains.",
            "example": "1"
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "TERM_FINANCE_0xABC…"
            },
            "description": "`TERM_FINANCE_<id>` lender key. See the `LenderId` schema for the full set of accepted values.",
            "example": "TERM_FINANCE_0xABC…"
          },
          {
            "name": "listingId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The listing id to cancel."
          },
          {
            "name": "skipRedeem",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Skip auto-redeem of the returned repo token (default false)."
          }
        ],
        "responses": {
          "200": {
            "description": "The `cancelListing` transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/liquity/open": {
      "post": {
        "tags": [
          "Actions › Liquity"
        ],
        "summary": "Open a trove",
        "operationId": "liquity-open",
        "description": "Open a trove: deposit collateral and mint stable debt at a user-set annual interest rate.\n\n**Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata.\n\n**Standard lending actions cover the day-to-day ops** for a `<DEPLOYMENT>_<chainId>_<COLL_INDEX>` market key:\n- stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel)\n- collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`)\n- borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`)\n- repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation)\n\nThe endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free.\n\nValidates the deployment's min debt + rate bounds, quotes SortedTroves insert hints and the `maxUpfrontFee` guard on-chain, and picks the next free owner index. Returns the transaction plus the collateral (+ gas-compensation WETH) approvals.\n\n`interestRate` is OPTIONAL: omit it and the trove opens at the **branch average** user-set rate (the rate the market data quotes as the branch borrow rate — mid-pack in the redemption queue). The applied rate is returned as `interestRate` in the response `data`; change it later with `POST /v1/actions/liquity/set-rate`.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/liquity/open`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Per-branch key, e.g. LIQUITY_V2_1_0 |\n| `account` | string | yes | Trove owner (tx sender) |\n| `collAmount` | string | yes | Collateral amount, raw units |\n| `amount` | string | yes | Stable debt to mint, raw units (≥ deployment minDebt) |\n| `interestRate` | string | no | Optional user-set annual rate, WAD (1e16 = 1%). Default: the branch average rate. |\n| `ownerIndex` | string | no | Optional explicit owner index (default: next free) |\n| `maxUpfrontFee` | string | no | Optional fee-guard override, raw stable units |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chainId",
                  "lender",
                  "account",
                  "collAmount",
                  "amount"
                ],
                "properties": {
                  "chainId": {
                    "type": "string",
                    "example": "1",
                    "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                  },
                  "lender": {
                    "type": "string",
                    "description": "Per-branch key, e.g. LIQUITY_V2_1_0",
                    "example": "LIQUITY_V2_1_0"
                  },
                  "account": {
                    "type": "string",
                    "description": "Trove owner (tx sender)"
                  },
                  "collAmount": {
                    "type": "string",
                    "description": "Collateral amount, raw units"
                  },
                  "amount": {
                    "type": "string",
                    "description": "Stable debt to mint, raw units (≥ deployment minDebt)"
                  },
                  "interestRate": {
                    "type": "string",
                    "description": "Optional user-set annual rate, WAD (1e16 = 1%). Default: the branch average rate.",
                    "example": "60000000000000000"
                  },
                  "ownerIndex": {
                    "type": "string",
                    "description": "Optional explicit owner index (default: next free)"
                  },
                  "maxUpfrontFee": {
                    "type": "string",
                    "description": "Optional fee-guard override, raw stable units"
                  }
                }
              },
              "example": {
                "chainId": "1",
                "lender": "LIQUITY_V2_1_0",
                "account": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                "collAmount": "1000000000000000000",
                "amount": "1000000000000000000",
                "interestRate": "60000000000000000",
                "ownerIndex": "string",
                "maxUpfrontFee": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Open-trove transaction + approvals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/liquity/close": {
      "get": {
        "tags": [
          "Actions › Liquity"
        ],
        "summary": "Close a trove",
        "operationId": "liquity-close",
        "description": "Close a trove: burns the FULL live `entireDebt` (incl. per-block interest accrual — keep a small stable buffer above any quote) from the sender and returns all collateral plus the gas compensation. Equivalent to `lending/repay` with `isAll=true`.\n\n**Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata.\n\n**Standard lending actions cover the day-to-day ops** for a `<DEPLOYMENT>_<chainId>_<COLL_INDEX>` market key:\n- stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel)\n- collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`)\n- borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`)\n- repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation)\n\nThe endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/liquity/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Per-branch key, e.g. LIQUITY_V2_1_0 See the `LenderId` schema for the full set of accepted values. |\n| `troveId` | query | string | yes | Trove id (sub-account id from user data) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chain id See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Per-branch key, e.g. LIQUITY_V2_1_0 See the `LenderId` schema for the full set of accepted values."
          },
          {
            "name": "troveId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Trove id (sub-account id from user data)"
          }
        ],
        "responses": {
          "200": {
            "description": "Close-trove transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/liquity/set-rate": {
      "post": {
        "tags": [
          "Actions › Liquity"
        ],
        "summary": "Adjust the user-set interest rate",
        "operationId": "liquity-set-rate",
        "description": "Change a trove's user-set annual interest rate. Free after the deployment's cooldown (7 days vanilla); within it, the upfront fee applies to the WHOLE debt — the `maxUpfrontFee` guard is quoted accordingly. Lower rates increase redemption risk (redemptions hit lowest-rate troves first).\n\n**Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata.\n\n**Standard lending actions cover the day-to-day ops** for a `<DEPLOYMENT>_<chainId>_<COLL_INDEX>` market key:\n- stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel)\n- collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`)\n- borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`)\n- repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation)\n\nThe endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/liquity/set-rate`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `troveId` | string | yes |  |\n| `interestRate` | string | yes | New annual rate, WAD |\n| `maxUpfrontFee` | string | no | Optional fee-guard override |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chainId",
                  "lender",
                  "troveId",
                  "interestRate"
                ],
                "properties": {
                  "chainId": {
                    "type": "string",
                    "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                  },
                  "lender": {
                    "type": "string",
                    "example": "LIQUITY_V2_1_0",
                    "description": "Protocol identifier. See the `LenderId` schema."
                  },
                  "troveId": {
                    "type": "string"
                  },
                  "interestRate": {
                    "type": "string",
                    "description": "New annual rate, WAD"
                  },
                  "maxUpfrontFee": {
                    "type": "string",
                    "description": "Optional fee-guard override"
                  }
                }
              },
              "example": {
                "chainId": "1",
                "lender": "LIQUITY_V2_1_0",
                "troveId": "string",
                "interestRate": "string",
                "maxUpfrontFee": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rate-adjust transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/liquity/claim-surplus": {
      "get": {
        "tags": [
          "Actions › Liquity"
        ],
        "summary": "Claim liquidation collateral surplus",
        "operationId": "liquity-claim-surplus",
        "description": "Claim the caller's post-liquidation collateral surplus on a branch (collateral above the liquidation penalty is escrowed in the CollSurplusPool).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/liquity/claim-surplus`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Per-branch key See the `LenderId` schema for the full set of accepted values. |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chain id See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Per-branch key See the `LenderId` schema for the full set of accepted values."
          }
        ],
        "responses": {
          "200": {
            "description": "Claim transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/liquity/adjust-zombie": {
      "post": {
        "tags": [
          "Actions › Liquity"
        ],
        "summary": "Re-adjust a zombie trove",
        "operationId": "liquity-adjust-zombie",
        "description": "Bring a ZOMBIE trove (redeemed below the deployment minDebt — status 4, removed from the rate-ordered list) back above the floor. `adjustZombieTrove` is the only adjustment entry for zombie troves; it re-inserts at the trove's current rate. Collateral top-ups add the collateral approval; debt increases charge the upfront fee.\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/liquity/adjust-zombie`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Protocol identifier. See the `LenderId` schema. |\n| `troveId` | string | yes |  |\n| `collChange` | string | no | Collateral delta, raw units |\n| `isCollIncrease` | boolean | no |  |\n| `boldChange` | string | no | Stable-debt delta, raw units |\n| `isDebtIncrease` | boolean | no |  |\n| `maxUpfrontFee` | string | no |  |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chainId",
                  "lender",
                  "troveId"
                ],
                "properties": {
                  "chainId": {
                    "type": "string",
                    "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                  },
                  "lender": {
                    "type": "string",
                    "description": "Protocol identifier. See the `LenderId` schema."
                  },
                  "troveId": {
                    "type": "string"
                  },
                  "collChange": {
                    "type": "string",
                    "description": "Collateral delta, raw units"
                  },
                  "isCollIncrease": {
                    "type": "boolean"
                  },
                  "boldChange": {
                    "type": "string",
                    "description": "Stable-debt delta, raw units"
                  },
                  "isDebtIncrease": {
                    "type": "boolean"
                  },
                  "maxUpfrontFee": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "chainId": "1",
                "lender": "AAVE_V3",
                "troveId": "string",
                "collChange": "string",
                "isCollIncrease": true,
                "boldChange": "string",
                "isDebtIncrease": true,
                "maxUpfrontFee": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Zombie-adjust transaction + approvals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/river/open": {
      "post": {
        "tags": [
          "Actions › River"
        ],
        "summary": "Open a trove",
        "operationId": "river-open",
        "description": "Open a trove on a River market: deposit collateral, mint satUSD.\n\n**River (rebranded Satoshi Protocol) is a Prisma-lineage pooled CDP** minting satUSD behind one SatoshiXApp diamond per chain (BNB, Base, Hemi). One TroveManager per collateral = one `RIVER_<chainId>_<TM_INDEX>` market; troves are keyed by OWNER ADDRESS — at most one per user per market, no ids. Interest is protocol-set (currently 0%); the only borrowing cost is a one-off decaying-baseRate mint fee (0.5%–5%) on open/borrow-more, guarded by `maxFeePercentage` (quoted automatically).\n\n**Standard lending actions cover the day-to-day ops:**\n- satUSD deposit/withdraw → the single per-chain Stability Pool (attached to market index 0; zero approvals)\n- collateral deposit/withdraw → `addColl`/`withdrawColl` (no troveId — address-keyed)\n- borrow → `withdrawDebt` (mint fee applies)\n- repay → `repayDebt` clamped to `entireDebt − gasComp − minNetDebt`; `isAll=true` routes to `closeTrove` (burns `entireDebt − gasComp` from the wallet, returns all collateral; blocked in Recovery Mode)\n\nThe 2-satUSD debt-side gas compensation is minted on open and burned from the GasPool on close — it never touches the wallet.\n\nValidates the diamond-level minNetDebt and rejects paused/sunsetting markets; quotes the mint-fee guard live. Returns the transaction plus the collateral approval (to the diamond).\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/river/open`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `lender` | string | yes | Per-market key, e.g. RIVER_8453_0 |\n| `account` | string | yes | Trove owner (tx sender) |\n| `collAmount` | string | yes | Collateral amount, raw units |\n| `amount` | string | yes | satUSD debt to mint, raw units (net ≥ minNetDebt) |\n| `maxFeePercentage` | string | no | Optional mint-fee guard override, WAD percentage |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chainId",
                  "lender",
                  "account",
                  "collAmount",
                  "amount"
                ],
                "properties": {
                  "chainId": {
                    "type": "string",
                    "example": "8453",
                    "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                  },
                  "lender": {
                    "type": "string",
                    "description": "Per-market key, e.g. RIVER_8453_0",
                    "example": "RIVER_8453_0"
                  },
                  "account": {
                    "type": "string",
                    "description": "Trove owner (tx sender)"
                  },
                  "collAmount": {
                    "type": "string",
                    "description": "Collateral amount, raw units"
                  },
                  "amount": {
                    "type": "string",
                    "description": "satUSD debt to mint, raw units (net ≥ minNetDebt)"
                  },
                  "maxFeePercentage": {
                    "type": "string",
                    "description": "Optional mint-fee guard override, WAD percentage"
                  }
                }
              },
              "example": {
                "chainId": "8453",
                "lender": "RIVER_8453_0",
                "account": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                "collAmount": "1000000000000000000",
                "amount": "1000000000000000000",
                "maxFeePercentage": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Open-trove transaction + approval",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/river/close": {
      "get": {
        "tags": [
          "Actions › River"
        ],
        "summary": "Close the trove",
        "operationId": "river-close",
        "description": "Close the caller's trove on a market: burns `entireDebt − gasCompensation` satUSD from the wallet, returns all collateral. Blocked in Recovery Mode (global TCR < 150%). Equivalent to `lending/repay` with `isAll=true`.\n\n**River (rebranded Satoshi Protocol) is a Prisma-lineage pooled CDP** minting satUSD behind one SatoshiXApp diamond per chain (BNB, Base, Hemi). One TroveManager per collateral = one `RIVER_<chainId>_<TM_INDEX>` market; troves are keyed by OWNER ADDRESS — at most one per user per market, no ids. Interest is protocol-set (currently 0%); the only borrowing cost is a one-off decaying-baseRate mint fee (0.5%–5%) on open/borrow-more, guarded by `maxFeePercentage` (quoted automatically).\n\n**Standard lending actions cover the day-to-day ops:**\n- satUSD deposit/withdraw → the single per-chain Stability Pool (attached to market index 0; zero approvals)\n- collateral deposit/withdraw → `addColl`/`withdrawColl` (no troveId — address-keyed)\n- borrow → `withdrawDebt` (mint fee applies)\n- repay → `repayDebt` clamped to `entireDebt − gasComp − minNetDebt`; `isAll=true` routes to `closeTrove` (burns `entireDebt − gasComp` from the wallet, returns all collateral; blocked in Recovery Mode)\n\nThe 2-satUSD debt-side gas compensation is minted on open and burned from the GasPool on close — it never touches the wallet.\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/river/close`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Per-market key, e.g. RIVER_8453_0 See the `LenderId` schema for the full set of accepted values. |\n| `operator` | query | string | yes | Trove owner |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chain id See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Per-market key, e.g. RIVER_8453_0 See the `LenderId` schema for the full set of accepted values."
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Trove owner"
          }
        ],
        "responses": {
          "200": {
            "description": "Close-trove transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/river/claim-surplus": {
      "get": {
        "tags": [
          "Actions › River"
        ],
        "summary": "Claim collateral surplus",
        "operationId": "river-claim-surplus",
        "description": "Claim the caller's post-liquidation/redemption collateral surplus on a market (`TroveManager.claimCollateral`). Surplus balances are visible in user data (`riverInfo.collateralSurplus`).\n\n<details>\n<summary>Plain-text reference — `GET /v1/actions/river/claim-surplus`</summary>\n\n**Parameters**\n\n| Parameter | In | Type | Required | Description |\n| --- | --- | --- | --- | --- |\n| `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. |\n| `lender` | query | string | yes | Per-market key See the `LenderId` schema for the full set of accepted values. |\n| `operator` | query | string | yes | Recipient (the surplus owner) |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object | Informational data (quotes, simulation results, etc.) |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {},\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "parameters": [
          {
            "name": "chainId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chain id See the `ChainId` schema for the full set of supported chains."
          },
          {
            "name": "lender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Per-market key See the `LenderId` schema for the full set of accepted values."
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Recipient (the surplus owner)"
          }
        ],
        "responses": {
          "200": {
            "description": "Claim transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {},
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/actions/allocate": {
      "post": {
        "tags": [
          "Allocate"
        ],
        "summary": "Allocate (multi-op batch)",
        "description": "Bundles multiple lending and token operations into a single composer transaction. Useful for portfolio rebalances, atomic deposit-then-borrow flows, or wrap/unwrap + deposit combos that should not be split across separate user signatures.\n\n**Request body:** `{ chainId, operator, actions[] }`. Each `actions[]` entry is `{ type, params }` where `type` is one of `Deposit | Withdraw | Borrow | Repay | Transfer | Wrap | Unwrap | Sweep`. The `params` shape is action-specific (asset, amount, market, etc.) — see the `AllocationAction` schema.\n\n**Response:** a single composer-call payload (`operations` / `data` / `value`) ready to send to the composer contract, plus `permissionTxns` for any required ERC20 approvals or borrow delegations.\n\nReturns 422 with field-level details if validation fails (unknown action type, missing required params, incompatible chain/lender combo).\n\n<details>\n<summary>Plain-text reference — `POST /v1/actions/allocate`</summary>\n\n**Request body**\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. |\n| `operator` | string | yes |  |\n| `actions` | object[] | yes |  |\n| `actions[].type` | `Deposit`, `Withdraw`, `Borrow`, `Repay`, `Transfer`, `Wrap`, … (8 values) | yes |  |\n| `actions[].params` | object | yes |  |\n\n**Response `200`**\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `success` | `True` |  |\n| `data` | object |  |\n| `data.operations` | string |  |\n| `data.data` | string | Informational payload. `null` when the endpoint only builds calldata. |\n| `data.value` | string | Native-token value to send with the transaction, in wei. |\n| `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. |\n| `data.permissionTxns[].to` | string | Target contract address |\n| `data.permissionTxns[].data` | string | Encoded calldata |\n| `data.permissionTxns[].value` | string | ETH value |\n| `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n| `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |\n| `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |\n| `actions.transactions[].to` | string | Target contract address |\n| `actions.transactions[].data` | string | Encoded calldata |\n| `actions.transactions[].value` | string | ETH value to send with the transaction |\n| `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |\n| `actions.alternatives[].to` | string | Target contract address |\n| `actions.alternatives[].data` | string | Encoded calldata |\n| `actions.alternatives[].value` | string | ETH value to send with the transaction |\n| `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\"). |\n| `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |\n| `actions.permissions[].to` | string | Target contract address |\n| `actions.permissions[].data` | string | Encoded calldata |\n| `actions.permissions[].value` | string | ETH value |\n| `actions.permissions[].description` | string | Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\") |\n| `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. |\n\n**Example response**\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"operations\": \"string\",\n    \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n    \"value\": \"1000000000000000000\",\n    \"permissionTxns\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  },\n  \"actions\": {\n    \"transactions\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"alternatives\": [\n      {\n        \"to\": \"0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\"\n      }\n    ],\n    \"permissions\": [\n      {\n        \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n        \"data\": \"0x617ba037000000000000000000000000c02aaa39b2\",\n        \"value\": \"0\",\n        \"description\": \"string\",\n        \"spender\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"\n      }\n    ]\n  }\n}\n```\n\n</details>\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AllocateRequest"
              },
              "example": {
                "chainId": "1",
                "operator": "0xOperatorAddress",
                "actions": [
                  {
                    "type": "Deposit",
                    "params": {}
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Allocation transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "nullable": true,
                      "$ref": "#/components/schemas/AllocateResponse",
                      "description": "Informational data (quotes, simulation results, etc.)"
                    },
                    "actions": {
                      "nullable": true,
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/ActionSet"
                        }
                      ],
                      "description": "Transaction calldata and approvals. Null for quote-only responses (no account provided)."
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "operations": "string",
                    "data": "0x617ba037000000000000000000000000c02aaa39b2",
                    "value": "1000000000000000000",
                    "permissionTxns": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  },
                  "actions": {
                    "transactions": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "alternatives": [
                      {
                        "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string"
                      }
                    ],
                    "permissions": [
                      {
                        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
                        "data": "0x617ba037000000000000000000000000c02aaa39b2",
                        "value": "0",
                        "description": "string",
                        "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation failed (e.g. unknown action type, missing required params)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error. Safe to retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          },
          "502": {
            "description": "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.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "MISSING_PARAM",
                    "message": "Missing required parameter: chainId"
                  }
                }
              }
            }
          }
        },
        "operationId": "allocate-multi-op-batch"
      }
    }
  },
  "components": {
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable error code",
            "example": "MISSING_PARAM"
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Missing required parameter: chainId"
          },
          "details": {
            "description": "Additional error context (varies by error code)"
          }
        },
        "description": "Machine-readable failure detail. `code` is stable and safe to branch on; `message` is for humans and may change."
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "$ref": "#/components/schemas/ApiError"
          }
        },
        "description": "Standard error response envelope. Returned for every failure regardless of status code, so branch on `success` rather than on the HTTP status."
      },
      "ActionSet": {
        "type": "object",
        "required": [
          "transactions"
        ],
        "properties": {
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRequest"
            },
            "description": "Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed."
          },
          "alternatives": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRequest"
            },
            "description": "DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints."
          },
          "permissions": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed."
          }
        },
        "description": "Transaction calldata and required approvals returned by action endpoints."
      },
      "TransactionRequest": {
        "type": "object",
        "required": [
          "to",
          "data",
          "value"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Target contract address",
            "example": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
          },
          "data": {
            "type": "string",
            "description": "Encoded calldata",
            "example": "0x617ba037000000000000000000000000c02aaa39b2"
          },
          "value": {
            "type": "string",
            "description": "ETH value to send with the transaction",
            "example": "0"
          },
          "description": {
            "type": "string",
            "description": "Human-readable label. For `alternatives`, this is the aggregator name (e.g. \"Paraswap\"). For `transactions`, describes the setup action (e.g. \"Switch e-mode to 1\")."
          }
        },
        "description": "An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them."
      },
      "PermissionTransaction": {
        "type": "object",
        "required": [
          "to",
          "data",
          "value"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Target contract address"
          },
          "data": {
            "type": "string",
            "description": "Encoded calldata"
          },
          "value": {
            "type": "string",
            "description": "ETH value",
            "example": "0"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the approval (e.g. \"Approve borrow for AAVE_V3\", \"Approve ERC20\")"
          },
          "spender": {
            "type": "string",
            "description": "ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description."
          }
        },
        "description": "An approval or delegation that must be mined before the main transaction. Already filtered against on-chain state, so every entry returned is genuinely missing."
      },
      "RateMetric": {
        "type": "object",
        "description": "A current/projected pair for a single rate metric.",
        "required": [
          "current",
          "projected"
        ],
        "properties": {
          "current": {
            "type": "number",
            "description": "Current value"
          },
          "projected": {
            "type": "number",
            "description": "Projected value after the action"
          }
        }
      },
      "RateImpactItem": {
        "type": "object",
        "description": "Projected interest-rate impact on a single market. Each item is keyed by `marketUid` so the client knows which market the rates refer to.",
        "required": [
          "marketUid",
          "utilization",
          "borrowRate",
          "depositRate"
        ],
        "properties": {
          "marketUid": {
            "type": "string",
            "description": "Market identifier (format: `lender:chainId:address`)",
            "example": "AAVE_V3:8453:0x4200000000000000000000000000000000000006"
          },
          "utilization": {
            "$ref": "#/components/schemas/RateMetric",
            "description": "Utilization ratio (0–1)",
            "example": {
              "current": 0.85,
              "projected": 0.83
            }
          },
          "borrowRate": {
            "$ref": "#/components/schemas/RateMetric",
            "description": "Borrow APR (%)",
            "example": {
              "current": 3.2,
              "projected": 3
            }
          },
          "depositRate": {
            "$ref": "#/components/schemas/RateMetric",
            "description": "Deposit/supply APR (%)",
            "example": {
              "current": 2.1,
              "projected": 1.9
            }
          }
        }
      },
      "LendingRawResponse": {
        "type": "object",
        "description": "Response from direct-mode lending operations (deposit, withdraw, borrow, repay).",
        "required": [
          "transaction",
          "permissionTxns"
        ],
        "properties": {
          "transaction": {
            "$ref": "#/components/schemas/TransactionRequest"
          },
          "permissionTxns": {
            "type": "array",
            "description": "Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances.",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            }
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          }
        }
      },
      "LendingProxyResponse": {
        "type": "object",
        "description": "Response from proxy-mode lending operations (via 1delta composer).",
        "required": [
          "transaction",
          "permissionTxns"
        ],
        "properties": {
          "transaction": {
            "$ref": "#/components/schemas/TransactionRequest"
          },
          "permissionTxns": {
            "type": "array",
            "description": "Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances.",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            }
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          }
        }
      },
      "SimulationBody": {
        "type": "object",
        "description": "Request body for POST variants of action endpoints. Provides the current portfolio state so the API can project post-trade metrics (health factor, borrow capacity, APRs) before and after the trade.\n\n**Data source:** All fields come directly from the `/v1/data/lending/user-positions` endpoint. For a given lender + sub-account, use:\n\n```\nGET /v1/data/lending/user-positions?account=0x...&chains=1\n\n// response.data.items[] is an array of lender entries.\n// Pick the entry matching your target lender + chain:\nconst lenderEntry = response.data.items.find(e => e.lender === 'AAVE_V3' && e.chainId === '1')\n\n// Each lenderEntry.data[] contains sub-accounts (usually one, index 0):\nconst subAccount = lenderEntry.data[0]\n\n// POST body for any action endpoint:\n{\n  \"balanceData\": subAccount.balanceData,\n  \"aprData\":     subAccount.aprData,\n  \"positions\":   subAccount.positions,\n  \"modeId\":      subAccount.userConfig.selectedMode  // optional\n}\n```\n\nIf the body is omitted, the API fetches balances on-chain automatically (slower, no simulation in response).",
        "required": [
          "balanceData",
          "aprData"
        ],
        "properties": {
          "balanceData": {
            "$ref": "#/components/schemas/BalanceData"
          },
          "aprData": {
            "$ref": "#/components/schemas/AprData"
          },
          "modeId": {
            "type": "string",
            "description": "Mode/config key from `userConfig.selectedMode` (defaults to \"0\")",
            "example": "0"
          },
          "positions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SimulationPosition"
            },
            "description": "Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections."
          }
        }
      },
      "SimulationPosition": {
        "type": "object",
        "description": "A single lending position as returned by user-data endpoints. Pass positions through as-is — the API enriches them internally with protocol-specific metadata.",
        "required": [
          "marketUid",
          "depositsUSD",
          "debtUSD",
          "debtStableUSD",
          "collateralEnabled"
        ],
        "properties": {
          "marketUid": {
            "type": "string",
            "description": "Unique market identifier (format: `{lender}:{chainId}:{address}`)",
            "example": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
          },
          "depositsUSD": {
            "type": "number",
            "description": "Deposit amount in USD",
            "example": 5000
          },
          "debtUSD": {
            "type": "number",
            "description": "Variable debt in USD",
            "example": 2000
          },
          "debtStableUSD": {
            "type": "number",
            "description": "Stable debt in USD",
            "example": 0
          },
          "collateralEnabled": {
            "type": "boolean",
            "description": "Whether this asset is enabled as collateral",
            "example": true
          }
        }
      },
      "SimulationPreState": {
        "type": "object",
        "description": "Portfolio state before the trade.",
        "properties": {
          "healthFactor": {
            "type": "number",
            "description": "Health factor before the trade (null-safe: capped at 1e18 when no debt)",
            "example": 1.85
          },
          "borrowCapacity": {
            "type": "number",
            "description": "Borrow capacity (USD) before the trade",
            "example": 3000
          }
        }
      },
      "SimulationPostState": {
        "type": "object",
        "description": "Projected portfolio state after the trade.",
        "properties": {
          "healthFactor": {
            "type": "number",
            "description": "Projected health factor after the trade",
            "example": 2.1
          },
          "borrowCapacity": {
            "type": "number",
            "description": "Projected borrow capacity (USD) after the trade",
            "example": 3500
          },
          "balanceData": {
            "$ref": "#/components/schemas/BalanceData"
          },
          "aprData": {
            "$ref": "#/components/schemas/AprData"
          }
        }
      },
      "PostTradeMetrics": {
        "type": "object",
        "description": "Projected portfolio metrics after a single-asset lending action (deposit, withdraw, borrow, repay). Pre-trade state is provided for comparison.",
        "properties": {
          "pre": {
            "$ref": "#/components/schemas/SimulationPreState"
          },
          "post": {
            "$ref": "#/components/schemas/SimulationPostState"
          }
        }
      },
      "LoopPostTradeMetrics": {
        "type": "object",
        "description": "Projected portfolio metrics after a multi-asset loop action (leverage, close, collateral-swap, debt-swap). Pre-trade state is provided for comparison.",
        "properties": {
          "pre": {
            "$ref": "#/components/schemas/SimulationPreState"
          },
          "post": {
            "$ref": "#/components/schemas/SimulationPostState"
          }
        }
      },
      "LendingRawSimulationResponse": {
        "type": "object",
        "description": "Direct-mode lending response enriched with post-trade simulation. Returned on POST (with body) or GET with `simulate=true`.",
        "required": [
          "transaction",
          "permissionTxns"
        ],
        "properties": {
          "transaction": {
            "$ref": "#/components/schemas/TransactionRequest"
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          },
          "simulation": {
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/PostTradeMetrics"
              }
            ],
            "description": "Projected post-trade metrics, or null if simulation failed"
          },
          "simulationError": {
            "type": "string",
            "description": "Error message if simulation failed"
          }
        }
      },
      "LendingProxySimulationResponse": {
        "type": "object",
        "description": "Proxy-mode lending response enriched with post-trade simulation. Returned on POST (with body) or GET with `simulate=true`.",
        "required": [
          "transaction",
          "permissionTxns"
        ],
        "properties": {
          "transaction": {
            "$ref": "#/components/schemas/TransactionRequest"
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          },
          "simulation": {
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/PostTradeMetrics"
              }
            ],
            "description": "Projected post-trade metrics, or null if simulation failed"
          },
          "simulationError": {
            "type": "string",
            "description": "Error message if simulation failed"
          }
        }
      },
      "RangeResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeveragePair"
          }
        ],
        "type": "object",
        "description": "Leverage pair metadata enriched with the computed max open amount. Inherits all fields from LeveragePair.",
        "required": [
          "amountIn",
          "amountOut",
          "amountUSD"
        ],
        "properties": {
          "amountIn": {
            "type": "number",
            "description": "Max open amount in the short (debt) asset units",
            "example": 1.5
          },
          "amountOut": {
            "type": "number",
            "description": "Max open amount in the long (collateral) asset units",
            "example": 1.2
          },
          "amountUSD": {
            "type": "number",
            "description": "Max open amount in USD",
            "example": 3000
          },
          "payAmountUSD": {
            "type": "number",
            "description": "USD value of the zap deposit (only present when payAmount query param is provided)",
            "example": 2300
          },
          "modeAnalysis": {
            "type": "object",
            "description": "E-mode switching analysis (only present in multi-pair mode)",
            "properties": {
              "userMode": {
                "type": "string",
                "description": "User's current e-mode ID",
                "example": "0"
              },
              "targetMode": {
                "type": "string",
                "description": "Pair's optimal e-mode ID",
                "example": "2"
              },
              "canSwitchToTargetMode": {
                "type": "boolean",
                "description": "Whether user can switch to the target mode without conflicting positions"
              },
              "userModeRange": {
                "$ref": "#/components/schemas/RangeAmounts",
                "description": "Range in the user's current mode (null if pair disabled in that mode)"
              },
              "targetModeRange": {
                "$ref": "#/components/schemas/RangeAmounts",
                "description": "Range in the pair's optimal mode"
              }
            }
          }
        }
      },
      "RangeAmounts": {
        "type": "object",
        "description": "Amount triplet returned by all range endpoints.",
        "required": [
          "amountIn",
          "amountOut",
          "amountUSD"
        ],
        "properties": {
          "amountIn": {
            "type": "number",
            "description": "Amount in the input asset units",
            "example": 1.5
          },
          "amountOut": {
            "type": "number",
            "description": "Amount in the output asset units",
            "example": 1.2
          },
          "amountUSD": {
            "type": "number",
            "description": "Amount in USD",
            "example": 3000
          }
        }
      },
      "CollateralSwapRangeResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeveragePair"
          }
        ],
        "type": "object",
        "description": "Max swappable collateral. amountUSD = depositsUSD of the source collateral position.",
        "required": [
          "amountIn",
          "amountOut",
          "amountUSD"
        ],
        "properties": {
          "amountIn": {
            "type": "number",
            "description": "Max amount of source collateral to withdraw (in asset units)",
            "example": 5000
          },
          "amountOut": {
            "type": "number",
            "description": "Equivalent amount in the target collateral asset units",
            "example": 5000
          },
          "amountUSD": {
            "type": "number",
            "description": "Max swappable amount in USD",
            "example": 5000
          }
        }
      },
      "DebtSwapRangeResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeveragePair"
          }
        ],
        "type": "object",
        "description": "Max swappable debt. amountUSD = debtUSD + debtStableUSD of the source debt position.",
        "required": [
          "amountIn",
          "amountOut",
          "amountUSD",
          "denomination"
        ],
        "properties": {
          "amountIn": {
            "type": "number",
            "description": "Max amount of source debt to repay (in asset units)",
            "example": 4
          },
          "amountOut": {
            "type": "number",
            "description": "Equivalent amount in the target debt asset units",
            "example": 3.5
          },
          "amountUSD": {
            "type": "number",
            "description": "Max swappable amount in USD",
            "example": 8000
          },
          "denomination": {
            "type": "string",
            "enum": [
              "exactInput",
              "exactOutput"
            ],
            "description": "Which side is the base denomination"
          }
        }
      },
      "CloseRangeResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeveragePair"
          }
        ],
        "type": "object",
        "description": "Max closeable amount. Bounded by min(collateral, debt).",
        "required": [
          "amountIn",
          "amountOut",
          "amountUSD",
          "denomination"
        ],
        "properties": {
          "amountIn": {
            "type": "number",
            "description": "Max collateral to withdraw (in long asset units)",
            "example": 3.5
          },
          "amountOut": {
            "type": "number",
            "description": "Max debt to repay (in short asset units)",
            "example": 4
          },
          "amountUSD": {
            "type": "number",
            "description": "Max closeable amount in USD (min of collateral and debt)",
            "example": 8000
          },
          "denomination": {
            "type": "string",
            "enum": [
              "exactInput",
              "exactOutput"
            ],
            "description": "Which side is the base denomination"
          }
        }
      },
      "MarginSimulationQuoteResponse": {
        "type": "object",
        "description": "Quote-only loop response enriched with post-trade simulation (POST only).",
        "required": [
          "lender",
          "quotes"
        ],
        "properties": {
          "lender": {
            "type": "string",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "deltas": {
                  "$ref": "#/components/schemas/QuoteDelta"
                },
                "rateImpact": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RateImpactItem"
                  },
                  "description": "Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable."
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          },
          "simulation": {
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/LoopPostTradeMetrics"
              }
            ],
            "description": "Projected post-trade metrics, or null if simulation failed"
          },
          "simulationError": {
            "type": "string",
            "description": "Error message if simulation failed"
          }
        }
      },
      "MarginSimulationBuildResponse": {
        "type": "object",
        "description": "Full build loop response enriched with post-trade simulation (POST only).",
        "required": [
          "lender",
          "quotes",
          "permissionTxns"
        ],
        "properties": {
          "lender": {
            "type": "string",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "deltas": {
                  "$ref": "#/components/schemas/QuoteDelta"
                },
                "tx": {
                  "$ref": "#/components/schemas/TransactionRequest"
                },
                "rateImpact": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RateImpactItem"
                  },
                  "description": "Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable."
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          },
          "simulation": {
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/LoopPostTradeMetrics"
              }
            ],
            "description": "Projected post-trade metrics, or null if simulation failed"
          },
          "simulationError": {
            "type": "string",
            "description": "Error message if simulation failed"
          }
        }
      },
      "QuoteDelta": {
        "type": "object",
        "properties": {
          "aggregator": {
            "type": "string",
            "description": "Aggregator source"
          },
          "tradeInput": {
            "type": "number",
            "description": "Trade input amount"
          },
          "tradeOutput": {
            "type": "number",
            "description": "Trade output amount"
          },
          "deltas": {
            "type": "object",
            "additionalProperties": true,
            "description": "Balance deltas"
          }
        }
      },
      "MarginQuoteResponse": {
        "type": "object",
        "description": "Quote-only response (no account provided). No transaction is built.",
        "required": [
          "lender",
          "quotes"
        ],
        "properties": {
          "lender": {
            "type": "string",
            "description": "Protocol identifier"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "deltas": {
                  "$ref": "#/components/schemas/QuoteDelta"
                },
                "rateImpact": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RateImpactItem"
                  },
                  "description": "Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable."
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          }
        }
      },
      "MarginBuildResponse": {
        "type": "object",
        "description": "Full build response (account provided). Includes transaction calldata.",
        "required": [
          "lender",
          "quotes",
          "permissionTxns"
        ],
        "properties": {
          "lender": {
            "type": "string",
            "description": "Protocol identifier"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "deltas": {
                  "$ref": "#/components/schemas/QuoteDelta"
                },
                "tx": {
                  "$ref": "#/components/schemas/TransactionRequest"
                },
                "rateImpact": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RateImpactItem"
                  },
                  "description": "Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable."
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          },
          "rateImpact": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RateImpactItem"
            },
            "description": "Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable."
          }
        }
      },
      "SpotQuoteResponse": {
        "type": "object",
        "description": "Quote-only response for spot swap (no account provided).",
        "required": [
          "currencyIn",
          "currencyOut",
          "quotes"
        ],
        "properties": {
          "currencyIn": {
            "type": "object",
            "additionalProperties": true,
            "description": "Input currency info"
          },
          "currencyOut": {
            "type": "object",
            "additionalProperties": true,
            "description": "Output currency info"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "aggregator": {
                  "type": "string"
                },
                "tradeInput": {
                  "type": "number"
                },
                "tradeOutput": {
                  "type": "number"
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          }
        }
      },
      "SpotBuildResponse": {
        "type": "object",
        "description": "Full build response for spot swap (account provided).",
        "required": [
          "currencyIn",
          "currencyOut",
          "quotes",
          "permissionTxns"
        ],
        "properties": {
          "currencyIn": {
            "type": "object",
            "additionalProperties": true,
            "description": "Input currency info"
          },
          "currencyOut": {
            "type": "object",
            "additionalProperties": true,
            "description": "Output currency info"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "aggregator": {
                  "type": "string"
                },
                "tradeInput": {
                  "type": "number"
                },
                "tradeOutput": {
                  "type": "number"
                },
                "tx": {
                  "$ref": "#/components/schemas/TransactionRequest"
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          }
        }
      },
      "XChainQuoteResponse": {
        "type": "object",
        "description": "Quote-only response for cross-chain swap (no account provided).",
        "required": [
          "currencyIn",
          "currencyOut",
          "quotes"
        ],
        "properties": {
          "currencyIn": {
            "type": "object",
            "additionalProperties": true,
            "description": "Input currency info (source chain)"
          },
          "currencyOut": {
            "type": "object",
            "additionalProperties": true,
            "description": "Output currency info (destination chain)"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "bridge": {
                  "type": "string"
                },
                "tradeInput": {
                  "type": "number"
                },
                "tradeOutput": {
                  "type": "number"
                },
                "estimatedDuration": {
                  "type": "number",
                  "description": "Estimated bridging duration in seconds"
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          }
        }
      },
      "XChainBuildResponse": {
        "type": "object",
        "description": "Full build response for cross-chain swap (account provided).",
        "required": [
          "currencyIn",
          "currencyOut",
          "quotes",
          "permissionTxns"
        ],
        "properties": {
          "currencyIn": {
            "type": "object",
            "additionalProperties": true,
            "description": "Input currency info (source chain)"
          },
          "currencyOut": {
            "type": "object",
            "additionalProperties": true,
            "description": "Output currency info (destination chain)"
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "bridge": {
                  "type": "string"
                },
                "tradeInput": {
                  "type": "number"
                },
                "tradeOutput": {
                  "type": "number"
                },
                "estimatedDuration": {
                  "type": "number",
                  "description": "Estimated bridging duration in seconds"
                },
                "approvalTarget": {
                  "type": "string",
                  "description": "This bridge's deposit contract — the ERC-20 approve spender"
                },
                "approvalRequired": {
                  "type": "boolean",
                  "description": "False when the existing on-chain allowance already covers the input amount"
                },
                "tx": {
                  "$ref": "#/components/schemas/TransactionRequest"
                }
              }
            },
            "description": "Candidate routes, best output first. Execute exactly one."
          },
          "permissionTxns": {
            "type": "array",
            "description": "ERC-20 approves per bridge deposit contract; each is labeled with the bridge name — execute only the one matching the chosen quote",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            }
          }
        }
      },
      "AllocationOperation": {
        "type": "string",
        "enum": [
          "Deposit",
          "Withdraw",
          "Borrow",
          "Repay",
          "Transfer",
          "Wrap",
          "Unwrap",
          "Sweep"
        ]
      },
      "AllocationAction": {
        "type": "object",
        "required": [
          "type",
          "params"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/AllocationOperation"
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "AllocateRequest": {
        "type": "object",
        "required": [
          "chainId",
          "operator",
          "actions"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "operator": {
            "type": "string",
            "example": "0xOperatorAddress"
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AllocationAction"
            }
          }
        }
      },
      "AllocateResponse": {
        "type": "object",
        "required": [
          "operations",
          "data",
          "value",
          "permissionTxns"
        ],
        "properties": {
          "operations": {
            "type": "string"
          },
          "data": {
            "type": "string",
            "description": "Informational payload. `null` when the endpoint only builds calldata."
          },
          "value": {
            "type": "string",
            "description": "Native-token value to send with the transaction, in wei."
          },
          "permissionTxns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionTransaction"
            },
            "description": "Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead."
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "properties": {
          "latestHour": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Latest data generation hour"
          }
        }
      },
      "ChainsResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of supported chains"
          },
          "items": {
            "type": "array",
            "description": "Supported chains, sorted ascending by numeric chainId.",
            "items": {
              "type": "object",
              "required": [
                "chainId",
                "name",
                "logoURI"
              ],
              "properties": {
                "chainId": {
                  "type": "string",
                  "description": "Decimal EVM chain id, as a string.",
                  "example": "1"
                },
                "name": {
                  "type": "string",
                  "description": "Human-readable display name. Prefers the registry `shortName` (concise, e.g. \"eth\"); falls back to the long `name`, then to \"Chain {id}\".",
                  "example": "eth"
                },
                "logoURI": {
                  "type": "string",
                  "format": "uri",
                  "description": "Absolute URL to the chain icon. Always populated; consumers should handle broken images gracefully.",
                  "example": "https://raw.githubusercontent.com/1delta-DAO/chains/main/1.webp"
                }
              }
            }
          }
        }
      },
      "RpcsResponse": {
        "type": "object",
        "description": "Chain ID to array of RPC URLs. Keys are chain IDs; values are arrays of RPC endpoint URLs.",
        "additionalProperties": {
          "type": "array",
          "items": {
            "type": "string",
            "description": "RPC endpoint URL"
          }
        }
      },
      "PriceResponse": {
        "type": "object",
        "properties": {
          "asOf": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp the data was measured at."
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "items": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Map of asset_group → priceUsd",
            "example": {
              "USDC": 1.0001,
              "WBTC": 67432.12
            }
          },
          "debug": {
            "type": "object",
            "properties": {
              "rows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "IntrinsicYieldResponse": {
        "type": "object",
        "properties": {
          "asOf": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp the data was measured at."
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "intrinsicApr": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Map of asset_group → APR in percent",
            "example": {
              "USDC": 3.25,
              "ETH": 2.1
            }
          }
        }
      },
      "IntrinsicYieldSnapshotResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "series": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/IntrinsicYieldPoint"
              }
            },
            "description": "Map of assetGroup → array of {dataTs, intrinsicYield}"
          }
        }
      },
      "IntrinsicYieldPoint": {
        "type": "object",
        "properties": {
          "dataTs": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp the data was measured at."
          },
          "intrinsicYield": {
            "type": "number"
          }
        }
      },
      "LenderYieldResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Informational payload. `null` when the endpoint only builds calldata."
          }
        }
      },
      "LenderInfo": {
        "type": "object",
        "description": "Protocol/lender metadata (name, logo).",
        "properties": {
          "key": {
            "type": "string",
            "description": "Lender key identifier",
            "example": "AAVE_V3"
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable lender name",
            "example": "Aave V3"
          },
          "logoURI": {
            "type": "string",
            "nullable": true,
            "description": "Lender logo URL",
            "example": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp"
          }
        }
      },
      "MarketAssetInfo": {
        "type": "object",
        "description": "Token metadata for an underlying asset.",
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "address": {
            "type": "string",
            "description": "Token contract address (lowercase)",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
          },
          "symbol": {
            "type": "string",
            "example": "USDC",
            "description": "Token symbol, e.g. `WETH`."
          },
          "name": {
            "type": "string",
            "example": "USD Coin",
            "description": "Human-readable display name."
          },
          "decimals": {
            "type": "integer",
            "nullable": true,
            "example": 6,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "logoURI": {
            "type": "string",
            "nullable": true,
            "description": "URL of the logo image."
          },
          "assetGroup": {
            "type": "string",
            "nullable": true,
            "description": "Canonical asset group (e.g. \"USDC\", \"ETH\", \"BTC\")",
            "example": "USDC"
          },
          "currencyId": {
            "type": "string",
            "nullable": true
          },
          "props": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Protocol-specific asset properties"
          }
        }
      },
      "MarketPriceInfo": {
        "type": "object",
        "description": "Market prices for an asset with 24h comparison.",
        "properties": {
          "priceUsd": {
            "type": "number",
            "nullable": true,
            "description": "Current price in USD"
          },
          "priceTs": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of current price"
          },
          "priceUsd24h": {
            "type": "number",
            "nullable": true,
            "description": "Price 24 hours ago in USD"
          },
          "priceTs24h": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of 24h-ago price"
          },
          "priceChange24h": {
            "type": "number",
            "nullable": true,
            "description": "Percentage price change over 24h"
          }
        }
      },
      "MarketOraclePrice": {
        "type": "object",
        "description": "On-chain oracle price data.",
        "properties": {
          "oraclePrice": {
            "type": "number",
            "nullable": true,
            "description": "Raw on-chain oracle price"
          },
          "oraclePriceUsd": {
            "type": "number",
            "nullable": true,
            "description": "Oracle price denominated in USD"
          }
        }
      },
      "MarketUnderlyingInfo": {
        "type": "object",
        "description": "Nested asset metadata, oracle prices, and market prices for a lending market.",
        "properties": {
          "asset": {
            "$ref": "#/components/schemas/MarketAssetInfo"
          },
          "oraclePrice": {
            "$ref": "#/components/schemas/MarketOraclePrice"
          },
          "prices": {
            "$ref": "#/components/schemas/MarketPriceInfo"
          }
        }
      },
      "OracleFeed": {
        "type": "object",
        "description": "Classification of one price-oracle feed backing a market, from the oracle-risk pipeline.",
        "properties": {
          "asset": {
            "type": "string",
            "nullable": true,
            "description": "Priced asset symbol (the reported numerator)."
          },
          "oracle": {
            "type": "string",
            "nullable": true,
            "description": "Oracle / feed / adapter address (lowercased)."
          },
          "provider": {
            "type": "string",
            "nullable": true,
            "description": "Oracle mechanism: `chainlink`, `redstone`, `pyth`, `chronicle`, `composite`, `price-cap` (Aave PriceCapAdapter), `exchange-rate` (correlated/LST, e.g. Venus OneJumpOracle), `pendle-pt`, `constant`, or a lender-specific stub (`compound-v2-oracle`, `dolomite-oracle`, `fluid-oracle`)."
          },
          "priceDescription": {
            "type": "string",
            "nullable": true,
            "description": "Decoded reported pair, e.g. `\"WBTC / USD\"`; `\"UNKNOWN\"` when the source could not be decoded."
          },
          "intendedPair": {
            "type": "string",
            "nullable": true,
            "description": "What the feed *should* report: `\"<asset> / <numeraire>\"`."
          },
          "correctOracle": {
            "type": "boolean",
            "nullable": true,
            "description": "Does the feed price the intended **asset** (numerator match)? `null` = unverifiable."
          },
          "denominatorMatch": {
            "type": "boolean",
            "nullable": true,
            "description": "Is the feed denominated in the right **numeraire** (e.g. the loan token / market unit)? `null` = unknown."
          },
          "fixedRate": {
            "type": "boolean",
            "description": "Hardcoded/constant price feed."
          },
          "score": {
            "type": "integer",
            "description": "Feed risk score 0–100. See `OracleInfo` for the model."
          },
          "band": {
            "type": "string",
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ],
            "description": "Risk band for `score`."
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Risk flags: `wrong-asset`, `correlated-proxy`, `cross-numeraire`, `undecoded-source`, `fixed-rate`, `unrecognized-provider`."
          }
        }
      },
      "OracleInfo": {
        "type": "object",
        "nullable": true,
        "description": "Oracle feed-correctness classification for the market's price oracle(s). `null` when the market has no oracle classification.\n\nThis 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.\n\n**Scoring (per feed, additive):** `score = provider base + flag penalties`, clamped 0–100.\n\nProvider base (oracle mechanism; first match wins):\n\n| Provider | Base |\n|---|---|\n| `chainlink`, `price-cap` | 10 |\n| `redstone`/`pyth`/`chronicle`/… and *unrecognized* | 18 |\n| `composite` / cross-feed | 22 |\n| `exchange-rate` / `pendle-pt` / LST rate adapters | 28 |\n| `twap`/`uniswap`/DEX | 30 |\n| `fixed-rate` / `constant` | 55 |\n\nFlag penalties (added on top): `wrong-asset` +45 · `correlated-proxy` +18 · `cross-numeraire` +18 · `undecoded-source` +8.\n\nBands: **LOW** < 25 · **MEDIUM** 25–49 · **HIGH** 50–74 · **CRITICAL** ≥ 75.",
        "required": [
          "feeds",
          "worstScore",
          "worstBand"
        ],
        "properties": {
          "feeds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OracleFeed"
            },
            "description": "Per-feed classifications, ordered worst-first."
          },
          "worstScore": {
            "type": "integer",
            "description": "Highest (worst) `score` across `feeds`."
          },
          "worstBand": {
            "type": "string",
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ],
            "description": "Band of the worst feed."
          }
        }
      },
      "MarketFlags": {
        "type": "object",
        "description": "Boolean flags describing the operational status of a lending market. Values may be null if unavailable from the protocol.",
        "properties": {
          "isActive": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the market is active"
          },
          "isFrozen": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the market is frozen (no new deposits/borrows)"
          },
          "hasStable": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether stable-rate borrowing is available"
          },
          "borrowingEnabled": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether borrowing is enabled"
          },
          "depositsEnabled": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether deposits are enabled"
          },
          "collateralActive": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the asset can be used as collateral"
          },
          "variableBorrowDisabled": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether variable-rate borrowing is unavailable through 1delta for this market. `true` for Lista DAO fixed-term (brokered) markets, where borrows must go through the broker and pick a fixed term from `terms[]`. Together with a non-empty `terms[]` this is the canonical \"brokered market\" signal — such markets report `variableBorrowRate = 0` but cannot be borrowed variably."
          }
        }
      },
      "MarketCaps": {
        "type": "object",
        "description": "Supply, borrow, and debt ceiling caps for a lending market.",
        "properties": {
          "borrowCap": {
            "type": "number",
            "nullable": true,
            "description": "Maximum borrowable amount (token units)"
          },
          "supplyCap": {
            "type": "number",
            "nullable": true,
            "description": "Maximum depositable amount (token units)"
          },
          "debtCeiling": {
            "type": "string",
            "nullable": true,
            "description": "Isolation-mode debt ceiling"
          }
        }
      },
      "MarketConfigEntry": {
        "type": "object",
        "description": "Risk parameters for a specific e-mode or collateral category.",
        "properties": {
          "category": {
            "type": "string",
            "description": "E-mode category identifier",
            "example": "1"
          },
          "label": {
            "type": "string",
            "description": "Human-readable label for this config category",
            "example": "ETH correlated"
          },
          "borrowCollateralFactor": {
            "type": "number",
            "nullable": true,
            "description": "LTV for borrowing (0-1)",
            "example": 0.8
          },
          "collateralFactor": {
            "type": "number",
            "nullable": true,
            "description": "Liquidation threshold (0-1)",
            "example": 0.85
          },
          "borrowFactor": {
            "type": "number",
            "nullable": true,
            "description": "Borrow factor (typically 1)",
            "example": 1
          },
          "liquidationPenalty": {
            "type": "number",
            "nullable": true,
            "description": "Liquidation penalty for this mode, as a fraction of repaid debt the liquidator receives on top of par (e.g. 0.05 = 5%). Mode-specific where supported (Aave e-modes, Dolomite categories, Euler vaults).",
            "example": 0.05
          },
          "closeFactor": {
            "type": "number",
            "nullable": true,
            "description": "Max fraction of debt repayable per liquidation (0-1). Mirrors the pool-level closeFactor; not e-mode-specific in any supported protocol, so the same value across every mode of a market.",
            "example": 0.5
          },
          "targetHealthFactor": {
            "type": "number",
            "nullable": true,
            "description": "Liquidation target health factor (e.g. 1.05). Set only by protocols that liquidate to a target HF instead of a fixed close factor (Aave V4, spoke-level); omitted otherwise.",
            "example": 1.05
          },
          "collateralDisabled": {
            "type": "boolean"
          },
          "debtDisabled": {
            "type": "boolean"
          }
        }
      },
      "UserRewardEntry": {
        "type": "object",
        "description": "A claimable reward token entry for a user position.",
        "properties": {
          "asset": {
            "type": "string",
            "description": "Reward token contract address",
            "example": "0xc00e94Cb662C3520282E6f5717214004A7f26888"
          },
          "totalRewards": {
            "type": "number",
            "description": "Total accumulated rewards (token units)",
            "example": 12.5
          },
          "claimableRewards": {
            "type": "number",
            "description": "Immediately claimable rewards (token units)",
            "example": 12.5
          }
        }
      },
      "RewardAprBreakdown": {
        "type": "object",
        "description": "APR breakdown for a single reward token.",
        "properties": {
          "apr": {
            "type": "number",
            "description": "Net reward APR (normalized to NAV)",
            "example": 0.045
          },
          "borrowApr": {
            "type": "number",
            "description": "Reward APR on borrows",
            "example": 0.012
          },
          "depositApr": {
            "type": "number",
            "description": "Reward APR on deposits",
            "example": 0.078
          }
        }
      },
      "RewardEntry": {
        "type": "object",
        "description": "One reward program on a lending market, one entry per (reward token, source). A borrow-side APR REDUCES the cost of borrowing — dTRINITY dLEND is the extreme case, where the rebate exceeds the interest and the net borrow rate is negative. Rewards are NEVER folded into health-factor or liquidation math: those use the gross rate.",
        "properties": {
          "asset": {
            "type": "string",
            "description": "Reward token address, lowercased. For a points program (`kind: \"points\"`) there is no token and this is a synthetic `points:<sourceId>` key."
          },
          "symbol": {
            "type": "string",
            "nullable": true,
            "description": "Reward token symbol. Denormalized deliberately — reward tokens are routinely absent from the asset table (aMonUSDe, WMON, aHorRwaRLUSD are live examples), so a join would leave them unnamed."
          },
          "decimals": {
            "type": "integer",
            "nullable": true,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "logoURI": {
            "type": "string",
            "nullable": true,
            "description": "URL of the logo image."
          },
          "depositRate": {
            "type": "number",
            "description": "Reward APR on deposits"
          },
          "variableBorrowRate": {
            "type": "number",
            "description": "Reward APR on variable borrows"
          },
          "stableBorrowRate": {
            "type": "number",
            "description": "Reward APR on stable borrows"
          },
          "kind": {
            "type": "string",
            "nullable": true,
            "description": "`token` | `points`. Points are NOT priceable and must be shown separately from any headline APR."
          },
          "claim": {
            "type": "string",
            "nullable": true,
            "description": "How the reward is realized, i.e. whether the APR is bankable. `accrual` — claimable from the protocol on-chain; `merkl` — off-chain merkle distribution; `manual`."
          },
          "source": {
            "type": "string",
            "description": "LEGACY mechanism tag (`merkle`, `onchain-incentives`, `native`) — it cannot distinguish two programs on the same platform. Prefer `sourceId`."
          },
          "sourceId": {
            "type": "string",
            "nullable": true,
            "description": "Stable program identifier, safe to key on: `merkl:aave`, `merkl:euler`, `merkl:morpho`, `dtrinity:rebate`."
          },
          "sourceLabel": {
            "type": "string",
            "nullable": true,
            "description": "Display string for the program, e.g. `Merkl · Aave`."
          },
          "link": {
            "type": "string",
            "nullable": true,
            "description": "Deep link to THIS program — the exact Merkl opportunity page, not a protocol homepage."
          },
          "endsAt": {
            "type": "number",
            "nullable": true,
            "description": "Unix seconds the program stops paying. An APR with two weeks left is not the same product as a standing rate, so render it."
          },
          "startsAt": {
            "type": "number",
            "nullable": true
          },
          "dailyRewardsUsd": {
            "type": "number",
            "nullable": true,
            "description": "Program-wide payout rate in USD/day, as the source reports it."
          },
          "refs": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Platform identifiers verbatim — Merkl campaign ids and opportunity type, or the incentives-controller address for an on-chain program. For support and deduplication, not display."
          }
        }
      },
      "FixedTermInfo": {
        "type": "object",
        "description": "Canonical cross-protocol fixed-term market descriptor, served per lender key on fixed-rate / fixed-maturity markets (Lista brokered, Morpho Midnight, Term Finance, Exactly, Teller, TermMax). Absent on variable-rate lenders. The rate-card menu itself stays on `markets[].terms[]`; this carries the maturity, fee, early-repay and origination-window facts. Per-protocol repay/penalty economics are documented in FIXED_TERM_REPAY_TERMS.md.",
        "properties": {
          "model": {
            "type": "string",
            "enum": [
              "lista",
              "midnight",
              "term",
              "exactly",
              "teller",
              "termmax"
            ],
            "description": "Underlying fixed-term protocol shape.",
            "example": "term"
          },
          "maturity": {
            "type": "integer",
            "nullable": true,
            "description": "Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`)."
          },
          "fees": {
            "type": "object",
            "additionalProperties": true,
            "description": "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."
          },
          "earlyRepay": {
            "type": "object",
            "additionalProperties": true,
            "description": "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)."
          },
          "provider": {
            "type": "object",
            "additionalProperties": true,
            "description": "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."
          },
          "auction": {
            "$ref": "#/components/schemas/FixedTermAuction"
          }
        }
      },
      "FixedTermAuction": {
        "type": "object",
        "description": "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`.\n\nThis 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.",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "upcoming",
              "open",
              "revealing",
              "closed"
            ],
            "description": "`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.",
            "example": "open"
          },
          "canBorrow": {
            "type": "boolean",
            "description": "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.",
            "example": true
          },
          "canLend": {
            "type": "boolean",
            "description": "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.",
            "example": true
          },
          "secondsUntilClose": {
            "type": "integer",
            "nullable": true,
            "description": "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.",
            "example": 263000
          },
          "implications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "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."
          },
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Auction round id. Absent when `status: \"closed\"`."
          },
          "startTime": {
            "type": "integer",
            "nullable": true,
            "description": "Submissions open, unix seconds. Absent when closed."
          },
          "revealTime": {
            "type": "integer",
            "nullable": true,
            "description": "Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed."
          },
          "endTime": {
            "type": "integer",
            "nullable": true,
            "description": "Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed."
          },
          "minBorrowAmount": {
            "type": "string",
            "nullable": true,
            "description": "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.",
            "example": "1000000000"
          },
          "minLendAmount": {
            "type": "string",
            "nullable": true,
            "description": "Minimum offer (lend) size for this round, loan-token BASE units.",
            "example": "1000000000"
          }
        }
      },
      "MarketTerm": {
        "type": "object",
        "description": "A fixed-term entry in a rate card, in `LendingMarket.terms[]`. Emitted by every fixed-term lender (Lista broker, Midnight, Term Finance, Exactly, Teller, TermMax). Borrowers pick one and pass its `termId` to the borrow action. NOTE `termId` semantics differ per lender — see the field description.",
        "properties": {
          "termId": {
            "type": "integer",
            "description": "Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing.",
            "example": 2
          },
          "depositApr": {
            "type": "number",
            "nullable": true,
            "description": "Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides)."
          },
          "available": {
            "type": "number",
            "nullable": true,
            "description": "Borrowable liquidity at this maturity in loan-token human units (Exactly only)."
          },
          "durationDays": {
            "type": "number",
            "description": "How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30).",
            "example": 7
          },
          "durationSecs": {
            "type": "number",
            "nullable": true,
            "description": "Term duration in seconds (raw on-chain value).",
            "example": 604800
          },
          "apr": {
            "type": "number",
            "description": "Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate.",
            "example": 3.85
          },
          "aprAtAmount": {
            "type": "number",
            "nullable": true,
            "description": "Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size."
          },
          "fillable": {
            "type": "number",
            "nullable": true,
            "description": "Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied."
          },
          "capped": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP)."
          },
          "ladder": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "properties": {
                "apr": {
                  "type": "number",
                  "description": "Annualised borrow rate at this tier (%)."
                },
                "units": {
                  "type": "string",
                  "description": "Credit/debt units at this tier (raw)."
                },
                "assets": {
                  "type": "number",
                  "description": "Loan-token size available at this tier."
                }
              }
            },
            "description": "Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount."
          }
        }
      },
      "LoanTerm": {
        "type": "object",
        "description": "Per-loan fixed-term detail attached to a user position (`LendingPosition.term`), one per open loan. Emitted by Lista broker, Exactly, TermMax and Teller — several fields are lender-specific, and the repay economics behind them differ sharply per protocol (see FIXED_TERM_REPAY_TERMS.md). Lista only: the flexible/dynamic position uses `isDynamic = true` and the `type(uint128).max` `loanId` sentinel.",
        "properties": {
          "loanId": {
            "type": "string",
            "description": "The WRITE TARGET for this loan — meaning is lender-specific: Lista = the broker's posId (the dynamic position uses `340282366920938463463374607431768211455`, `type(uint128).max`); Exactly = the maturity as a string (but repay requests send `termId`, never `loanId`); TermMax = the GT NFT id; Teller = the bidId. Pass to `/v1/actions/lending/repay?loanId=…` for the lenders that key on it.",
            "example": "450"
          },
          "termId": {
            "type": "integer",
            "nullable": true,
            "description": "The rate-card term this loan was opened against (matches a `MarketTerm.termId`). Omitted for the dynamic/flex position. Exactly: equals the maturity, and IS the field a repay request must send.",
            "example": 2
          },
          "isDynamic": {
            "type": "boolean",
            "nullable": true,
            "description": "True for the flexible/variable position (e.g. a matured fixed loan auto-refinanced into the dynamic position). Omitted/false for fixed-term loans.",
            "example": false
          },
          "debt": {
            "type": "string",
            "description": "Outstanding debt for this loan in token units. Lista/Teller (accruing debt): principal + accrued interest. Exactly/TermMax (STATIC face value): the EXIT-NOW cost — for Exactly that is discounted before maturity and penalty-inflated when overdue, so compare with `faceValue` rather than assuming it is the settle-at-maturity amount.",
            "example": "14.5003"
          },
          "apr": {
            "type": "number",
            "nullable": true,
            "description": "Fixed APR locked for this loan, in **percent**. Omitted for the dynamic position (it tracks the variable rate).",
            "example": 3.85
          },
          "maturity": {
            "type": "number",
            "nullable": true,
            "description": "Unix timestamp (seconds) when the fixed term ends. After maturity interest is frozen and the loan may be refinanced into the dynamic position. Omitted for the dynamic position.",
            "example": 1781789025
          },
          "termDays": {
            "type": "number",
            "nullable": true,
            "description": "Term length in days.",
            "example": 7
          },
          "accruedInterest": {
            "type": "string",
            "nullable": true,
            "description": "Interest accrued so far on this loan, in token units.",
            "example": "0.000358"
          },
          "earlyRepayPenalty": {
            "type": "string",
            "nullable": true,
            "description": "Cost (token units) to close this loan **before maturity**, on top of principal + accrued interest (≈ half the remaining-term interest). `0` once the loan has matured. To fully close fund `debt + earlyRepayPenalty`; the broker refunds any excess.",
            "example": "0.001211"
          },
          "isMatured": {
            "type": "boolean",
            "nullable": true,
            "description": "True once the fixed term has ended. What follows differs per lender: Lista freezes interest and a keeper auto-converts the loan into the dynamic position (so it may reappear as the `isDynamic` row); Exactly starts accruing the late penalty below; TermMax opens a 2-hour liquidation window and then settles by physical delivery; Teller DEFAULTS after the market grace period and a liquidator seizes the entire collateral.",
            "example": false
          },
          "faceValue": {
            "type": "string",
            "nullable": true,
            "description": "Amount owed AT maturity (principal + fee) for static-face-value lenders (Exactly). No accrual index — it grows only via a late penalty where the protocol has one. Compare against `debt` (the exit-now cost) to show the user what waiting or repaying early is worth.",
            "example": "100.0"
          },
          "earlyRepayDiscount": {
            "type": "string",
            "nullable": true,
            "description": "Exactly only: the REBATE for repaying before maturity (`faceValue − debt`). Exactly never charges an early-repay fee — but this is `0` when the fixed pool has no unassigned earnings left, so an early repay is not a guaranteed saving. Opposite in sign to Lista `earlyRepayPenalty`.",
            "example": "1.0"
          },
          "latePenalty": {
            "type": "string",
            "nullable": true,
            "description": "Exactly only: penalty accrued so far past maturity (`debt − faceValue`), token units.",
            "example": "2.25"
          },
          "latePenaltyPerDay": {
            "type": "string",
            "nullable": true,
            "description": "Exactly only: further penalty per additional day overdue, token units. LINEAR on face value, not compounding.",
            "example": "0.225"
          },
          "latePenaltyApr": {
            "type": "number",
            "nullable": true,
            "description": "Exactly only: the annualized late-penalty rate in percent (~164 %/yr ≙ ~0.45 %/day at time of writing). A mutable market parameter, snapshotted per fetch — do not hardcode it in UI copy.",
            "example": 164.24
          },
          "secondsLate": {
            "type": "integer",
            "nullable": true,
            "description": "Seconds past maturity; `0` until overdue.",
            "example": 0
          }
        }
      },
      "LendingMarket": {
        "type": "object",
        "description": "Enriched lending market data as returned by /lending and /pools endpoints. Numeric fields are parsed to number | null.",
        "properties": {
          "lenderKey": {
            "type": "string",
            "description": "Protocol identifier",
            "example": "AAVE_V3"
          },
          "poolId": {
            "type": "string",
            "description": "Pool/vault address or protocol-specific ID"
          },
          "depositRate": {
            "type": "number",
            "nullable": true,
            "description": "Deposit APR (percent)"
          },
          "variableBorrowRate": {
            "type": "number",
            "nullable": true,
            "description": "Variable borrow APR (percent)"
          },
          "stableBorrowRate": {
            "type": "number",
            "nullable": true,
            "description": "Stable borrow APR (percent)"
          },
          "intrinsicYield": {
            "type": "number",
            "nullable": true,
            "description": "Intrinsic yield APR from underlying asset (e.g. stETH staking)"
          },
          "totalDeposits": {
            "type": "number",
            "nullable": true,
            "description": "Total deposits in token units"
          },
          "totalDebtStable": {
            "type": "number",
            "nullable": true,
            "description": "Total stable debt in token units"
          },
          "totalDebt": {
            "type": "number",
            "nullable": true,
            "description": "Total variable debt in token units"
          },
          "totalLiquidity": {
            "type": "number",
            "nullable": true,
            "description": "Available liquidity (totalDeposits - totalDebt) in token units"
          },
          "totalDepositsUsd": {
            "type": "number",
            "nullable": true,
            "description": "Total deposits in USD"
          },
          "totalDebtStableUsd": {
            "type": "number",
            "nullable": true,
            "description": "Total stable debt in USD"
          },
          "totalDebtUsd": {
            "type": "number",
            "nullable": true,
            "description": "Total variable debt in USD"
          },
          "totalLiquidityUsd": {
            "type": "number",
            "nullable": true,
            "description": "Available liquidity in USD"
          },
          "utilization": {
            "type": "number",
            "nullable": true,
            "description": "Utilization ratio (totalDebt / totalDeposits)"
          },
          "decimals": {
            "type": "integer",
            "nullable": true,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "underlyingInfo": {
            "$ref": "#/components/schemas/MarketUnderlyingInfo"
          },
          "oracleInfo": {
            "$ref": "#/components/schemas/OracleInfo"
          },
          "caps": {
            "$ref": "#/components/schemas/MarketCaps"
          },
          "flags": {
            "$ref": "#/components/schemas/MarketFlags"
          },
          "rewards": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RewardEntry"
            },
            "description": "Active reward programs. Defaults to [] when none."
          },
          "config": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/MarketConfigEntry"
            },
            "description": "Risk config keyed by mode/category ID (e.g. \"0\" for default, \"1\" for e-mode)"
          },
          "terms": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/MarketTerm"
            },
            "description": "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."
          },
          "broker": {
            "type": "string",
            "nullable": true,
            "description": "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).",
            "example": "0x1fa26015286d1270343d7526c60bd57ab6be8b54"
          },
          "collateralProvider": {
            "type": "string",
            "nullable": true,
            "description": "Lista DAO collateral-provider contract for this market. When set (non-zero), Moolah gates `supplyCollateral`/`withdrawCollateral` behind it, so collateral deposits/withdrawals must route through this provider rather than calling Moolah directly (the SDK/worker handle this). Set for markets whose collateral is a Lista-managed token (e.g. slisBNB); `null` for plain ERC-20 collateral.",
            "example": "0x33f7a980a246f9b8fea2254e3065576e127d4d5f"
          },
          "loanProvider": {
            "type": "string",
            "nullable": true,
            "description": "Lista DAO loan-token provider contract for this market (e.g. the native-WBNB wrapper provider). When set, loan-token operations are gated behind it; for brokered markets the broker handles the debt side. Informational — consumers do not pass it; the SDK/worker resolve routing automatically.",
            "example": "0x367384c54756a25340c63057d87ea22d47fd5701"
          },
          "closeFactor": {
            "type": "number",
            "nullable": true,
            "description": "Max fraction of a borrower's debt repayable in a single liquidation (0-1). Aave ~0.5 (rises to 1 below the close-factor health threshold), Compound V2 closeFactorMantissa; 1 (full liquidation) for isolated / credit-account protocols (Compound V3, Morpho, Euler, Fluid, Gearbox, Dolomite, Silo).",
            "example": 0.5
          },
          "targetHealthFactor": {
            "type": "number",
            "nullable": true,
            "description": "Liquidation target health factor (e.g. 1.05). Set only by protocols that liquidate to a target HF rather than a fixed close factor (Aave V4, spoke-level); omitted otherwise.",
            "example": 1.05
          },
          "lenderInfo": {
            "$ref": "#/components/schemas/LenderInfo"
          },
          "termSheet": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/TermSheetDigest"
              },
              {
                "$ref": "#/components/schemas/TermSheet"
              }
            ],
            "nullable": true,
            "description": "Structured description of this market’s lend and borrow offer. Shape depends on the `terms` query param: `digest` (default) or `full`. Absent when `terms=none`."
          }
        },
        "additionalProperties": true
      },
      "TermInfo": {
        "type": "object",
        "required": [
          "headline",
          "tags"
        ],
        "properties": {
          "headline": {
            "type": "string",
            "description": "Ready-to-render one-liner, templated from this market’s live numbers. ALWAYS populated — it is the graceful-degradation path when a client meets an enum member it predates.",
            "example": "Fixed 4.12% until 3 Sep 2026 · repay any time at face value"
          },
          "description": {
            "type": "string",
            "description": "Human-readable label for this entry."
          },
          "implications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Consequences a rate alone hides, ordered MOST SEVERE FIRST. Present only on `terms=full`."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Machine tags derived from the structured fields (never hand-written), e.g. `time-liquidation`, `full-collateral-seizure`, `redeemable`, `exit-cooldown`. Present in BOTH the digest and the full sheet, which is why severity can be computed from either."
          }
        }
      },
      "TermFee": {
        "type": "object",
        "description": "One charge. A NEGATIVE `value` is a REBATE (Exactly rebates early repayment) — sign is load-bearing, never take an absolute value.",
        "required": [
          "id",
          "label",
          "when",
          "unit",
          "basis",
          "value"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable slug: `origination`, `late-penalty`, `early-repay-discount`, `reserve-contribution`, `instant-exit`, `performance`, `reserve-factor`, …"
          },
          "label": {
            "type": "string",
            "description": "Self-describing, so an `id` a client does not recognise still renders correctly."
          },
          "when": {
            "type": "string",
            "description": "`entry` | `ongoing` | `exit` | `late` | `liquidation` | `performance`"
          },
          "unit": {
            "type": "string",
            "description": "`apr-percent` | `percent` | `bps` | `absolute`"
          },
          "basis": {
            "type": "string",
            "description": "`principal` | `face-value` | `yield` | `collateral` | `shares` | `debt-repaid`"
          },
          "value": {
            "type": "number",
            "description": "Native-token value to send with the transaction, in wei."
          },
          "payee": {
            "type": "string",
            "nullable": true
          },
          "mutable": {
            "type": "boolean",
            "nullable": true,
            "description": "Governance-mutable — a snapshot."
          },
          "indicative": {
            "type": "boolean",
            "nullable": true,
            "description": "Only resolvable at action time (Exactly’s discount, TermMax’s curve price)."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable label for this entry."
          }
        }
      },
      "TermRate": {
        "type": "object",
        "description": "All rates are NOMINAL APR in PERCENT (`3.85` = 3.85 %/yr) — never a fraction, never an APY.",
        "required": [
          "kind",
          "apr",
          "components",
          "aprTotal",
          "basis",
          "isLocked"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "description": "`variable-curve` | `variable-managed` | `user-set` | `fixed-term` | `zero-interest` | `prepaid` | `nav-accrual` | `none`. A `zero-interest` market is NOT a free borrow — the cost is a one-off fee."
          },
          "apr": {
            "type": "number",
            "description": "Base rate only."
          },
          "components": {
            "type": "object",
            "properties": {
              "base": {
                "type": "number"
              },
              "rewards": {
                "type": "number",
                "nullable": true,
                "description": "PRICEABLE rewards only."
              },
              "intrinsic": {
                "type": "number",
                "nullable": true
              }
            }
          },
          "aprTotal": {
            "type": "number",
            "description": "base + priceable rewards + intrinsic. Deliberately EXCLUDES points programs, which have no priceable value — see `rewards[].indicative`."
          },
          "basis": {
            "type": "string",
            "enum": [
              "apr-nominal"
            ]
          },
          "compounding": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "isLocked": {
            "type": "boolean"
          },
          "minApr": {
            "type": "number",
            "nullable": true
          },
          "maxApr": {
            "type": "number",
            "nullable": true
          },
          "userSet": {
            "type": "object",
            "nullable": true,
            "description": "Present when the BORROWER sets the rate (Liquity family). A borrow UI must render an input: the rate decides your place in the redemption queue, so the cheapest is also the first redeemed. Omit the rate on the action and the protocol applies `default` (the branch average).",
            "properties": {
              "required": {
                "type": "boolean"
              },
              "min": {
                "type": "number",
                "nullable": true
              },
              "max": {
                "type": "number",
                "nullable": true
              },
              "default": {
                "type": "number",
                "nullable": true
              },
              "adjustable": {
                "type": "boolean"
              },
              "adjustmentCostNote": {
                "type": "string",
                "nullable": true
              },
              "adjustmentCooldownSecs": {
                "type": "number",
                "nullable": true
              }
            }
          },
          "rewards": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "object",
                  "nullable": true,
                  "additionalProperties": true
                },
                "kind": {
                  "type": "string",
                  "description": "`token` | `points` | `unknown`"
                },
                "apr": {
                  "type": "number"
                },
                "side": {
                  "type": "string",
                  "enum": [
                    "supply",
                    "borrow"
                  ]
                },
                "claim": {
                  "type": "string",
                  "description": "`accrual` | `merkl` | `manual` | `none`"
                },
                "endsAt": {
                  "type": "number",
                  "nullable": true
                },
                "indicative": {
                  "type": "boolean",
                  "nullable": true,
                  "description": "Points — not priceable, and excluded from `aprTotal`."
                }
              }
            }
          },
          "menu": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/MarketTerm"
            }
          }
        }
      },
      "TermMaturity": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "description": "`perpetual` | `fixed-date` | `rolling-duration`"
          },
          "maturity": {
            "type": "number",
            "nullable": true,
            "description": "Unix seconds."
          },
          "maturityIso": {
            "type": "string",
            "nullable": true
          },
          "secondsToMaturity": {
            "type": "number",
            "nullable": true
          },
          "minDurationSecs": {
            "type": "number",
            "nullable": true
          },
          "maxDurationSecs": {
            "type": "number",
            "nullable": true
          },
          "atMaturity": {
            "type": "string",
            "nullable": true,
            "description": "What happens if NOBODY acts — the field that most surprises users. `stops-earning` | `penalty-accrues` | `liquidatable` | `default-seizure` | `physical-delivery` | `refinanced` | `auto-roll` | `none`."
          },
          "graceSecs": {
            "type": "number",
            "nullable": true,
            "description": "Window before `atMaturity` bites. Observed as low as 300 s (Teller)."
          }
        }
      },
      "TermRedemption": {
        "type": "object",
        "description": "Collateral taken from a HEALTHY position. On every lender we serve this is a PERMISSIONLESS ARBITRAGE that defends the stablecoin’s peg — not a liquidation, and not a governance decision. Rendering only the effect (\"your collateral can be taken\") misleads.",
        "required": [
          "trigger",
          "order"
        ],
        "properties": {
          "trigger": {
            "type": "string",
            "description": "`permissionless-arbitrage` — any holder of the debt token, any time. (`governance` / `protocol` are reserved and unused.)"
          },
          "driver": {
            "type": "string",
            "nullable": true,
            "description": "`below-peg` — it only pays them while the token trades under its target."
          },
          "order": {
            "type": "string",
            "description": "`lowest-rate-first` (Liquity family — your rate IS your queue position) | `pro-rata` (Resupply — every borrower is skimmed, nothing to out-run) | `lowest-collateral-ratio`."
          },
          "valueImpact": {
            "type": "string",
            "nullable": true,
            "description": "`usd-neutral` — the fee stays in the position as extra collateral, so the borrower loses EXPOSURE, not value. Do not render this as \"you lose your collateral\"."
          },
          "defence": {
            "type": "string",
            "nullable": true,
            "description": "What the borrower can do. ABSENT when `order: pro-rata` — there is nothing."
          }
        }
      },
      "TermLiquidation": {
        "type": "object",
        "required": [
          "trigger",
          "penalty",
          "closeFactor",
          "seizure"
        ],
        "properties": {
          "model": {
            "type": "string",
            "nullable": true,
            "description": "HOW it happens, distinct from what triggers it. `repay-seize` | `soft-band` (LlamaLend: gradual, reversible, penalty-free conversion inside the AMM — there is no single liquidation price) | `stability-pool` | `auction` (Frankencoin: no oracle, an owner-DECLARED price policed by a Dutch auction) | `default-seizure` | `delivery` | `none`."
          },
          "absorber": {
            "type": "string",
            "nullable": true
          },
          "reversible": {
            "type": "boolean",
            "nullable": true,
            "description": "`soft-band` only — being \"in liquidation\" is not terminal and unwinds if price recovers."
          },
          "trigger": {
            "type": "string",
            "description": "`price` | `time` | `price-and-time` | `redemption` | `none`. A `time` trigger liquidates a perfectly over-collateralised position; a health factor does NOT protect you."
          },
          "ltv": {
            "type": "number",
            "nullable": true,
            "description": "FRACTION (0.8 = 80 %)."
          },
          "liquidationLtv": {
            "type": "number",
            "nullable": true,
            "description": "FRACTION."
          },
          "penalty": {
            "type": "number",
            "description": "FRACTION of repaid debt."
          },
          "penalties": {
            "type": "array",
            "nullable": true,
            "description": "Named penalties where one number cannot express the model — Liquity charges differently depending on whether the Stability Pool absorbs the debt or it is redistributed.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "number",
                  "description": "Native-token value to send with the transaction, in wei."
                },
                "description": {
                  "type": "string",
                  "nullable": true,
                  "description": "Human-readable label for this entry."
                }
              }
            }
          },
          "closeFactor": {
            "type": "number"
          },
          "targetHealthFactor": {
            "type": "number",
            "nullable": true
          },
          "seizure": {
            "type": "string",
            "description": "`proportional` | `full-collateral`. The latter (Teller) means a liquidator takes the ENTIRE escrow, not the amount owed — roughly 2x the borrowed value at 50 % LTV."
          },
          "redeemable": {
            "type": "boolean",
            "nullable": true
          },
          "redemption": {
            "$ref": "#/components/schemas/TermRedemption"
          },
          "windowSecs": {
            "type": "number",
            "nullable": true
          },
          "gracePeriodSecs": {
            "type": "number",
            "nullable": true
          },
          "permissioned": {
            "type": "boolean",
            "nullable": true
          },
          "badDebt": {
            "type": "string",
            "nullable": true
          },
          "bandLtv": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "number"
            },
            "description": "`soft-band` only: collateral factor as a function of the band count chosen at open (0.991 at N=4 vs 0.886 at N=50). `ltv` reports the default N."
          },
          "defaultBands": {
            "type": "number",
            "nullable": true
          },
          "fullCloseBelowHealthFactor": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "TermExposure": {
        "type": "object",
        "description": "What backs a deposit (`supply.backedBy`) or what may be posted (`borrow.acceptedCollateral`).",
        "required": [
          "count",
          "weightBasis"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "weightBasis": {
            "type": "string",
            "description": "`debt` | `allocation` | `unweighted`. **`unweighted` means the ACCEPTED SET, not a measured split** — pooled lenders do not record on-chain which collateral backs which borrow, so `weightPct` is absent and a pie chart would be fabricated."
          },
          "worstRiskScore": {
            "type": "number",
            "nullable": true,
            "description": "1 (best) … 5 (worst)."
          },
          "worstOracleBand": {
            "type": "string",
            "nullable": true
          },
          "topWeightPct": {
            "type": "number",
            "nullable": true
          },
          "items": {
            "type": "array",
            "nullable": true,
            "description": "Omitted on `terms=digest`; each entry carries its own `marketUid` for resolution.",
            "items": {
              "type": "object",
              "properties": {
                "asset": {
                  "type": "object",
                  "additionalProperties": true
                },
                "marketUid": {
                  "type": "string",
                  "nullable": true,
                  "description": "Market identifier, formatted `lender:chainId:address`."
                },
                "via": {
                  "type": "string"
                },
                "weightPct": {
                  "type": "number",
                  "nullable": true
                },
                "ltv": {
                  "type": "number",
                  "nullable": true,
                  "description": "Loan-to-value ratio, as a fraction between 0 and 1."
                },
                "liquidationLtv": {
                  "type": "number",
                  "nullable": true
                },
                "oracle": {
                  "$ref": "#/components/schemas/TermOracle"
                },
                "quality": {
                  "type": "object",
                  "nullable": true,
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "TermOracle": {
        "type": "object",
        "nullable": true,
        "description": "The market’s price input. SINGULAR by construction at `marketUid` granularity — verified across the full classification, 0 markets carry more than one address.",
        "properties": {
          "kind": {
            "type": "string",
            "description": "`price-feed` | `nav-attested` | `none`. **`none` is a FACT, not missing data** (Teller liquidates on time and has no feed anywhere in its trigger; Frankencoin uses an owner-declared price)."
          },
          "address": {
            "type": "string",
            "nullable": true,
            "description": "Lowercased. The contract the protocol actually calls."
          },
          "components": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "provider": {
            "type": "string",
            "nullable": true
          },
          "priceDescription": {
            "type": "string",
            "nullable": true
          },
          "intendedPair": {
            "type": "string",
            "nullable": true
          },
          "correctAsset": {
            "type": "boolean",
            "nullable": true
          },
          "correctNumeraire": {
            "type": "boolean",
            "nullable": true
          },
          "score": {
            "type": "integer",
            "nullable": true,
            "description": "Normalized risk score — lower is safer."
          },
          "band": {
            "type": "string",
            "nullable": true,
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ]
          },
          "flags": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "mutability": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          }
        }
      },
      "TermGovernance": {
        "type": "object",
        "properties": {
          "mutability": {
            "type": "string",
            "description": "`immutable` | `governed` | `unknown`"
          },
          "controller": {
            "type": "string",
            "nullable": true
          },
          "controllerKind": {
            "type": "string",
            "nullable": true,
            "description": "EOA | SAFE | TIMELOCK | GOVERNOR | GOVERNANCE | CUSTOM | UNKNOWN"
          },
          "safe": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          },
          "timelockSecs": {
            "type": "number",
            "nullable": true,
            "description": "The holder’s NOTICE PERIOD before a queued parameter change lands. **NOT a withdrawal lock** — that is `supply.exit.cooldownSecs`. Never merge or sum the two."
          },
          "timelockUnknown": {
            "type": "boolean",
            "nullable": true,
            "description": "The controller IS a timelock but its delay could not be read. Distinct from \"no delay\" — reporting the latter would be a false alarm on the safest governance shape."
          },
          "tier": {
            "type": "string",
            "nullable": true
          },
          "score": {
            "type": "number",
            "nullable": true,
            "description": "Normalized risk score — lower is safer."
          },
          "powers": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "roles": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          },
          "asOfScreen": {
            "type": "number",
            "nullable": true,
            "description": "Governance screens refresh far slower than rates."
          }
        }
      },
      "TermUtilization": {
        "type": "object",
        "required": [
          "utilization",
          "basis"
        ],
        "properties": {
          "utilization": {
            "type": "number",
            "description": "0..1 FRACTION."
          },
          "basis": {
            "type": "string",
            "description": "`market` | `hub` | `liquidity-layer` | `pool`. NOT always this row: Fluid / Aave V4 / Gearbox set rates on a LARGER pool, and a rate simulation must shift `irmTotal*`, not the row totals."
          },
          "irmTotalDeposits": {
            "type": "number",
            "nullable": true
          },
          "irmTotalDebt": {
            "type": "number",
            "nullable": true
          },
          "targetUtilization": {
            "type": "number",
            "nullable": true
          },
          "kinkUtilization": {
            "type": "number",
            "nullable": true
          },
          "supplyCapUtilization": {
            "type": "number",
            "nullable": true
          },
          "borrowCapUtilization": {
            "type": "number",
            "nullable": true
          },
          "lockupRatio": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "TermAvailability": {
        "type": "object",
        "required": [
          "canOpen",
          "canClose",
          "gating"
        ],
        "properties": {
          "canOpen": {
            "type": "boolean",
            "description": "Gate the CTA on THIS and nothing else — it already folds in caps, freezes, auction windows and gating."
          },
          "canClose": {
            "type": "boolean"
          },
          "blockedBy": {
            "type": "string",
            "nullable": true
          },
          "gating": {
            "type": "string"
          },
          "minSize": {
            "type": "string",
            "nullable": true,
            "description": "Minimum to OPEN, RAW base units of this side’s asset. On borrow a minimum DEBT (Comet `baseBorrowMin`, Liquity `minDebt`, Maker `dust`, Resupply `minimumBorrowAmount`); on supply a minimum COLLATERAL (Frankencoin). A smaller amount REVERTS — validate before building."
          },
          "cap": {
            "type": "string",
            "nullable": true
          },
          "capUtilization": {
            "type": "number",
            "nullable": true
          },
          "requires": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "window": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          }
        }
      },
      "TermSupplySide": {
        "type": "object",
        "required": [
          "role",
          "rate",
          "maturity",
          "exit",
          "fees",
          "counterparty",
          "availability",
          "principal",
          "info"
        ],
        "properties": {
          "role": {
            "type": "string",
            "description": "`yield` | `collateral` | `both`"
          },
          "rate": {
            "$ref": "#/components/schemas/TermRate"
          },
          "maturity": {
            "$ref": "#/components/schemas/TermMaturity"
          },
          "exit": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string"
              },
              "settlement": {
                "type": "string",
                "description": "`sync` | `async`"
              },
              "cooldownSecs": {
                "type": "number",
                "nullable": true,
                "description": "How long YOUR money is locked."
              },
              "liquidity": {
                "type": "object",
                "nullable": true,
                "additionalProperties": true
              },
              "partialAllowed": {
                "type": "boolean"
              },
              "priceRisk": {
                "type": "string",
                "description": "`none` | `haircut-formula` | `market-price` | `may-be-impossible`"
              },
              "fees": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TermFee"
                }
              }
            }
          },
          "fees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TermFee"
            }
          },
          "backedBy": {
            "$ref": "#/components/schemas/TermExposure"
          },
          "modes": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "counterparty": {
            "type": "object",
            "additionalProperties": true
          },
          "availability": {
            "$ref": "#/components/schemas/TermAvailability"
          },
          "principal": {
            "type": "object",
            "additionalProperties": true
          },
          "info": {
            "$ref": "#/components/schemas/TermInfo"
          }
        }
      },
      "TermBorrowSide": {
        "type": "object",
        "required": [
          "rate",
          "maturity",
          "debtShape",
          "exit",
          "liquidation",
          "fees",
          "counterparty",
          "availability",
          "info"
        ],
        "properties": {
          "rate": {
            "$ref": "#/components/schemas/TermRate"
          },
          "maturity": {
            "$ref": "#/components/schemas/TermMaturity"
          },
          "debtShape": {
            "type": "string",
            "description": "`accruing` | `static-face` | `prepaid`. The biggest departure from variable-rate intuition: most fixed-term debt is a static face value fixed at trade time, so repaying early does not reduce it."
          },
          "exit": {
            "type": "object",
            "properties": {
              "earlyRepay": {
                "type": "string",
                "description": "`free` | `discount` | `penalty` | `market-price` | `not-allowed`. Note `discount` is a REBATE (Exactly) — assuming \"early = penalty\" is wrong in both directions."
              },
              "atMaturityCost": {
                "type": "string"
              },
              "lateBehaviour": {
                "type": "string"
              },
              "partialAllowed": {
                "type": "boolean"
              },
              "minDebt": {
                "type": "string",
                "nullable": true,
                "description": "Dust floor, RAW base units — bounds partial repayment too."
              },
              "overRepayReverts": {
                "type": "boolean",
                "nullable": true,
                "description": "Midnight: over-repay REVERTS; size exactly."
              },
              "fees": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TermFee"
                }
              }
            }
          },
          "liquidation": {
            "$ref": "#/components/schemas/TermLiquidation"
          },
          "acceptedCollateral": {
            "$ref": "#/components/schemas/TermExposure"
          },
          "modes": {
            "type": "array",
            "nullable": true,
            "description": "Non-default risk categories as DELTAS (Aave e-modes, Dolomite categories, Euler configs). `liquidation` above is the fully-resolved DEFAULT.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "fees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TermFee"
            }
          },
          "counterparty": {
            "type": "object",
            "additionalProperties": true
          },
          "availability": {
            "$ref": "#/components/schemas/TermAvailability"
          },
          "info": {
            "$ref": "#/components/schemas/TermInfo"
          }
        }
      },
      "TermSheet": {
        "type": "object",
        "description": "The full term sheet (`?terms=full`). Absence of a side is MEANINGFUL: no `borrow` means the market cannot be borrowed.",
        "required": [
          "schemaVersion",
          "asOf",
          "profileId"
        ],
        "properties": {
          "schemaVersion": {
            "type": "integer",
            "example": 1
          },
          "asOf": {
            "type": "number",
            "description": "Unix seconds — everything here is a snapshot."
          },
          "profileId": {
            "type": "string",
            "example": "exactly.fixed@v1"
          },
          "marketUid": {
            "type": "string",
            "description": "Market identifier, formatted `lender:chainId:address`."
          },
          "lender": {
            "type": "string",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "chainId": {
            "type": "string",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "asset": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "The market’s own underlying — needed to render `minSize` / `cap` / `minDebt`, which are RAW base units."
          },
          "supply": {
            "$ref": "#/components/schemas/TermSupplySide"
          },
          "borrow": {
            "$ref": "#/components/schemas/TermBorrowSide"
          },
          "governance": {
            "$ref": "#/components/schemas/TermGovernance"
          },
          "oracle": {
            "$ref": "#/components/schemas/TermOracle"
          },
          "utilization": {
            "$ref": "#/components/schemas/TermUtilization"
          },
          "constraints": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          },
          "coverage": {
            "type": "object",
            "nullable": true,
            "description": "Distinguishes \"does not apply here\" (`notApplicable`) from \"not classified yet\" (`pending`). A missing block is NEVER a claim of absence.",
            "additionalProperties": true
          }
        }
      },
      "TermSheetDigest": {
        "type": "object",
        "description": "The compact form (`?terms=digest`, the DEFAULT). Structurally different from the full sheet: `headline` and `tags` are HOISTED to each side root and there is no `info` object, no nested blocks and no `items[]`. Read it through a shape-tolerant accessor — `sheet.supply.info.tags` throws here.",
        "properties": {
          "schemaVersion": {
            "type": "integer"
          },
          "profileId": {
            "type": "string"
          },
          "marketUid": {
            "type": "string",
            "description": "Market identifier, formatted `lender:chainId:address`."
          },
          "supply": {
            "type": "object",
            "additionalProperties": true
          },
          "borrow": {
            "type": "object",
            "additionalProperties": true
          },
          "oracle": {
            "type": "object",
            "additionalProperties": true
          },
          "governance": {
            "type": "object",
            "additionalProperties": true
          },
          "utilization": {
            "type": "number",
            "nullable": true,
            "description": "Market utilization, as a fraction between 0 and 1."
          }
        }
      },
      "LendingLatestItem": {
        "type": "object",
        "description": "Aggregated lending data for a single lender on a single chain.",
        "required": [
          "chainId",
          "lenderInfo",
          "totalDepositsUsd",
          "totalDebtUsd",
          "tvlUsd",
          "markets"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "8453",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lenderInfo": {
            "$ref": "#/components/schemas/LenderInfo"
          },
          "lastFetched": {
            "type": "number",
            "nullable": true,
            "description": "Epoch ms of latest snapshot"
          },
          "totalDepositsUsd": {
            "type": "number",
            "description": "Total deposits across all markets in USD"
          },
          "totalDebtUsd": {
            "type": "number",
            "description": "Total debt across all markets in USD"
          },
          "tvlUsd": {
            "type": "number",
            "description": "Total value locked in USD (deposits - debt)"
          },
          "params": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Lender-specific parameters. Only present for Morpho/Lista lenders (e.g. `{ market: { … } }`)."
          },
          "fixedTerm": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FixedTermInfo"
              }
            ],
            "nullable": true,
            "description": "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."
          },
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LendingMarket"
            },
            "description": "Individual lending markets for this lender on this chain"
          }
        }
      },
      "LendingLatestResponse": {
        "type": "object",
        "description": "Latest lending market data as a flat list of lender/chain entries. Returns only the lender keys requested via `lenders=…` (max 20 per request).",
        "required": [
          "count",
          "items"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of lender/chain entries"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LendingLatestItem"
            },
            "description": "Flat array of lender/chain entries"
          }
        }
      },
      "LendingLendersItem": {
        "type": "object",
        "description": "Lightweight enumeration entry for a single (chainId, lenderKey) pair.",
        "required": [
          "chainId",
          "lenderInfo",
          "tvlUsd"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lenderInfo": {
            "$ref": "#/components/schemas/LenderInfo"
          },
          "tvlUsd": {
            "type": "number",
            "description": "Σ totalDepositsUsd − Σ totalDebtUsd over the lender's markets on this chain",
            "example": 1234567890.12
          },
          "lastFetched": {
            "type": "number",
            "nullable": true,
            "description": "Epoch ms of latest snapshot"
          }
        }
      },
      "LendingLendersResponse": {
        "type": "object",
        "description": "Enumeration of available (chainId, lenderKey) pairs sorted by tvlUsd descending.",
        "required": [
          "count",
          "items"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of items returned"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LendingLendersItem"
            },
            "description": "Lender entries sorted by tvlUsd descending"
          }
        }
      },
      "LendingSnapshotResponse": {
        "type": "object",
        "properties": {
          "markets": {
            "type": "integer",
            "description": "Number of distinct markets"
          },
          "totalPoints": {
            "type": "integer",
            "description": "Total data points across all markets"
          },
          "series": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/LendingSnapshotPoint"
              }
            },
            "description": "Map of marketUid → array of {dataTs, ...fields}"
          }
        }
      },
      "LendingSnapshotPoint": {
        "type": "object",
        "description": "Contains dataTs plus whichever fields were requested.",
        "properties": {
          "dataTs": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp the data was measured at."
          },
          "depositRate": {
            "type": "number"
          },
          "variableBorrowRate": {
            "type": "number"
          },
          "stableBorrowRate": {
            "type": "number"
          },
          "totalDeposits": {
            "type": "number"
          },
          "totalDebtStable": {
            "type": "number"
          },
          "totalDebt": {
            "type": "number"
          },
          "totalLiquidity": {
            "type": "number"
          },
          "totalDepositsUsd": {
            "type": "number"
          },
          "totalDebtStableUsd": {
            "type": "number"
          },
          "totalDebtUsd": {
            "type": "number"
          },
          "totalLiquidityUsd": {
            "type": "number"
          }
        }
      },
      "Pool": {
        "type": "object",
        "description": "Paginated pool row (snake_case, from DB). Used by /pools endpoint.",
        "properties": {
          "chain_id": {
            "type": "string",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender_key": {
            "type": "string"
          },
          "underlying_address": {
            "type": "string"
          },
          "asset_group": {
            "type": "string"
          },
          "deposit_rate": {
            "type": "number"
          },
          "variable_borrow_rate": {
            "type": "number"
          },
          "stable_borrow_rate": {
            "type": "number"
          },
          "intrinsic_yield": {
            "type": "number"
          },
          "utilization": {
            "type": "number",
            "description": "Market utilization, as a fraction between 0 and 1."
          },
          "total_deposits": {
            "type": "number"
          },
          "total_debt": {
            "type": "number"
          },
          "total_liquidity": {
            "type": "number"
          },
          "total_deposits_usd": {
            "type": "number"
          },
          "total_debt_usd": {
            "type": "number"
          },
          "total_liquidity_usd": {
            "type": "number"
          }
        }
      },
      "PoolsResponse": {
        "type": "object",
        "properties": {
          "start": {
            "type": "integer"
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "pools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Pool"
            }
          }
        }
      },
      "PoolWithMeta": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LendingMarket"
          }
        ],
        "type": "object",
        "description": "Enriched pool returned by /pools/latest. Extends LendingMarket with chain context, computed APR, price data, and exposure info.",
        "properties": {
          "chainId": {
            "type": "string",
            "description": "Chain ID"
          },
          "lender": {
            "type": "string",
            "description": "Protocol identifier"
          },
          "apr": {
            "type": "number",
            "description": "Effective APR (depositRate + intrinsicYield)"
          },
          "price": {
            "type": "number",
            "nullable": true,
            "description": "Current asset price in USD"
          },
          "histPrice": {
            "type": "number",
            "nullable": true,
            "description": "Asset price 24h ago in USD"
          },
          "exposure": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "chainId": {
                  "type": "string",
                  "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
                },
                "lender": {
                  "type": "string",
                  "description": "Protocol identifier. See the `LenderId` schema."
                },
                "poolId": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            },
            "description": "Cross-protocol exposure for the same underlying asset"
          }
        },
        "additionalProperties": true
      },
      "PoolsLatestResponse": {
        "type": "object",
        "description": "Enriched pool list returned by /pools/latest.",
        "properties": {
          "fetchedAt": {
            "type": "number",
            "description": "Epoch timestamp of last data fetch"
          },
          "chainIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "EVM chain ids, as decimal strings. See the `ChainId` schema."
          },
          "pools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PoolWithMeta"
            }
          }
        }
      },
      "LeveragePair": {
        "type": "object",
        "description": "Leverage pair with full rate, risk-factor, and liquidity fields for both collateral (long) and debt (short) sides.",
        "properties": {
          "chainId": {
            "type": "string",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "marketLongUid": {
            "type": "string",
            "description": "Market UID of the collateral side"
          },
          "marketShortUid": {
            "type": "string",
            "description": "Market UID of the debt side"
          },
          "marketNameLong": {
            "type": "string",
            "nullable": true,
            "description": "Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender."
          },
          "marketNameShort": {
            "type": "string",
            "nullable": true,
            "description": "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."
          },
          "curatorNameLong": {
            "type": "string",
            "nullable": true,
            "description": "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."
          },
          "curatorNameShort": {
            "type": "string",
            "nullable": true,
            "description": "Curator/brand of the debt (controller) market. Same semantics as curatorNameLong."
          },
          "assetLong": {
            "type": "string",
            "description": "Collateral asset address"
          },
          "assetShort": {
            "type": "string",
            "description": "Debt asset address"
          },
          "assetGroupLong": {
            "type": "string"
          },
          "assetGroupShort": {
            "type": "string"
          },
          "symbolLong": {
            "type": "string",
            "description": "Collateral token symbol"
          },
          "nameLong": {
            "type": "string",
            "description": "Collateral token name"
          },
          "symbolShort": {
            "type": "string",
            "description": "Debt token symbol"
          },
          "nameShort": {
            "type": "string",
            "description": "Debt token name"
          },
          "collateralFactorLong": {
            "type": "number",
            "description": "Liquidation collateral factor for the long side",
            "example": 0.94
          },
          "borrowCollateralFactorLong": {
            "type": "number",
            "description": "Borrow-adjusted collateral factor for the long side",
            "example": 0.92
          },
          "borrowFactorLong": {
            "type": "number",
            "description": "Borrow factor for the long side",
            "example": 1
          },
          "collateralDisabledLong": {
            "type": "boolean",
            "description": "Whether collateral is disabled for the long asset"
          },
          "debtDisabledLong": {
            "type": "boolean",
            "description": "Whether debt is disabled for the long asset"
          },
          "collateralFactorShort": {
            "type": "number",
            "description": "Liquidation collateral factor for the short side",
            "example": 0.94
          },
          "borrowCollateralFactorShort": {
            "type": "number",
            "description": "Borrow-adjusted collateral factor for the short side",
            "example": 0.92
          },
          "borrowFactorShort": {
            "type": "number",
            "description": "Borrow factor for the short side",
            "example": 1
          },
          "collateralDisabledShort": {
            "type": "boolean",
            "description": "Whether collateral is disabled for the short asset"
          },
          "debtDisabledShort": {
            "type": "boolean",
            "description": "Whether debt is disabled for the short asset"
          },
          "eModeConfigId": {
            "type": "string",
            "description": "E-mode configuration ID"
          },
          "eMode": {
            "type": "string",
            "description": "E-mode category"
          },
          "aprBase": {
            "type": "number",
            "description": "Base APR (deposit - borrow + intrinsic, before rewards)"
          },
          "aprTotal": {
            "type": "number",
            "description": "Total APR (base + rewards)"
          },
          "maxLeverage": {
            "type": "number",
            "description": "Highest leverage multiple reachable in this market."
          },
          "ltv": {
            "type": "number",
            "description": "Loan-to-value ratio (0-1)"
          },
          "depositRateLong": {
            "type": "number"
          },
          "variableBorrowRateShort": {
            "type": "number"
          },
          "intrinsicYieldLong": {
            "type": "number"
          },
          "intrinsicYieldShort": {
            "type": "number"
          },
          "variableBorrowDisabledShort": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs."
          },
          "termsShort": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/MarketTerm"
            },
            "description": "Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means \"not borrowable right now\" rather than \"no offers\" — read `fixedTerm.auction` for why."
          },
          "fixedTerm": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FixedTermInfo"
              }
            ],
            "nullable": true,
            "description": "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."
          },
          "rewardAprLong": {
            "type": "number",
            "description": "Total reward APR on the collateral side"
          },
          "rewardAprShort": {
            "type": "number",
            "description": "Total reward APR on the debt side"
          },
          "rewardsLong": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Reward programs for the collateral side"
          },
          "rewardsShort": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Reward programs for the debt side"
          },
          "totalDepositsLong": {
            "type": "number",
            "description": "Total deposits in token units (long side)"
          },
          "totalDebtLong": {
            "type": "number",
            "description": "Total debt in token units (long side)"
          },
          "totalLiquidityLong": {
            "type": "number",
            "description": "Total liquidity in token units (long side)"
          },
          "totalDepositsShort": {
            "type": "number",
            "description": "Total deposits in token units (short side)"
          },
          "totalDebtShort": {
            "type": "number",
            "description": "Total debt in token units (short side)"
          },
          "totalLiquidityShort": {
            "type": "number",
            "description": "Total liquidity in token units (short side)"
          },
          "totalDepositsUsdLong": {
            "type": "number"
          },
          "totalDebtUsdLong": {
            "type": "number"
          },
          "totalLiquidityUsdLong": {
            "type": "number"
          },
          "totalDepositsUsdShort": {
            "type": "number"
          },
          "totalDebtUsdShort": {
            "type": "number"
          },
          "totalLiquidityUsdShort": {
            "type": "number"
          },
          "borrowLiquidityShort": {
            "type": "number",
            "description": "Available borrow liquidity (debt side) in token units"
          },
          "withdrawLiquidityLong": {
            "type": "number",
            "description": "Available withdraw liquidity (collateral side) in token units"
          },
          "depositableLong": {
            "type": "number",
            "description": "Remaining deposit capacity (collateral side) in token units"
          },
          "utilizationLong": {
            "type": "number"
          },
          "utilizationShort": {
            "type": "number"
          },
          "underlyingInfoLong": {
            "type": "object",
            "description": "Collateral asset metadata including token info, market prices, and oracle prices",
            "properties": {
              "asset": {
                "type": "object",
                "additionalProperties": true,
                "description": "Token metadata (address, symbol, name, decimals, logoURI, assetGroup)"
              },
              "prices": {
                "type": "object",
                "additionalProperties": true,
                "description": "Market prices (priceUsd, priceUsd24h, priceChange24h)"
              },
              "oraclePrice": {
                "type": "object",
                "additionalProperties": true,
                "description": "On-chain oracle prices (oraclePrice, oraclePriceUsd)"
              }
            }
          },
          "underlyingInfoShort": {
            "type": "object",
            "description": "Debt asset metadata including token info, market prices, and oracle prices",
            "properties": {
              "asset": {
                "type": "object",
                "additionalProperties": true,
                "description": "Token metadata (address, symbol, name, decimals, logoURI, assetGroup)"
              },
              "prices": {
                "type": "object",
                "additionalProperties": true,
                "description": "Market prices (priceUsd, priceUsd24h, priceChange24h)"
              },
              "oraclePrice": {
                "type": "object",
                "additionalProperties": true,
                "description": "On-chain oracle prices (oraclePrice, oraclePriceUsd)"
              }
            }
          }
        },
        "additionalProperties": true
      },
      "OptimizerPair": {
        "type": "object",
        "description": "Optimizer pair for collateral/debt searches. May include computed maxDebtAmount or minCollateralAmount.",
        "properties": {
          "chainId": {
            "type": "string",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "fixedTerm": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FixedTermInfo"
              }
            ],
            "nullable": true,
            "description": "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."
          },
          "marketLongUid": {
            "type": "string",
            "description": "Market UID of the collateral side"
          },
          "marketShortUid": {
            "type": "string",
            "description": "Market UID of the debt side"
          },
          "marketNameLong": {
            "type": "string",
            "nullable": true,
            "description": "Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender."
          },
          "marketNameShort": {
            "type": "string",
            "nullable": true,
            "description": "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."
          },
          "curatorNameLong": {
            "type": "string",
            "nullable": true,
            "description": "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."
          },
          "curatorNameShort": {
            "type": "string",
            "nullable": true,
            "description": "Curator/brand of the debt (controller) market. Same semantics as curatorNameLong."
          },
          "assetLong": {
            "type": "string"
          },
          "assetShort": {
            "type": "string"
          },
          "assetGroupLong": {
            "type": "string"
          },
          "assetGroupShort": {
            "type": "string"
          },
          "symbolLong": {
            "type": "string",
            "description": "Collateral token symbol"
          },
          "nameLong": {
            "type": "string",
            "description": "Collateral token name"
          },
          "symbolShort": {
            "type": "string",
            "description": "Debt token symbol"
          },
          "nameShort": {
            "type": "string",
            "description": "Debt token name"
          },
          "aprBase": {
            "type": "number",
            "description": "Leverage-weighted net APR % EXCLUDING rewards — the SUSTAINABLE rate (reward incentives are typically transient)."
          },
          "aprTotal": {
            "type": "number",
            "description": "Leverage-weighted net APR % INCLUDING rewards. The reward contribution is aprTotal − aprBase."
          },
          "maxLeverage": {
            "type": "number",
            "description": "Highest leverage multiple reachable in this market."
          },
          "ltv": {
            "type": "number",
            "description": "Loan-to-value ratio, as a fraction between 0 and 1."
          },
          "depositAprLong": {
            "type": "number",
            "description": "Effective deposit APR (depositRate + intrinsicYield)"
          },
          "borrowAprShort": {
            "type": "number",
            "description": "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)."
          },
          "originationFeeShort": {
            "type": "number",
            "nullable": true,
            "description": "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."
          },
          "totalDepositsUsdLong": {
            "type": "number"
          },
          "totalDepositsUsdShort": {
            "type": "number"
          },
          "totalDebtUsdLong": {
            "type": "number"
          },
          "totalDebtUsdShort": {
            "type": "number"
          },
          "totalLiquidityUsdLong": {
            "type": "number"
          },
          "totalLiquidityUsdShort": {
            "type": "number"
          },
          "borrowLiquidityShort": {
            "type": "number"
          },
          "utilizationLong": {
            "type": "number"
          },
          "utilizationShort": {
            "type": "number"
          },
          "maxDebtAmount": {
            "type": "number",
            "description": "Max borrowable amount given collateral (only when collateralAmount/collateralAmountUsd param provided)"
          },
          "maxDebtAmountUsd": {
            "type": "number",
            "description": "USD value of maxDebtAmount"
          },
          "minCollateralAmount": {
            "type": "number",
            "description": "Min collateral needed for debt amount (only when debtAmount/debtAmountUsd param provided)"
          },
          "minCollateralAmountUsd": {
            "type": "number",
            "description": "USD value of minCollateralAmount"
          },
          "borrowAprAtAmount": {
            "type": "number",
            "nullable": true,
            "description": "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."
          },
          "depositAprAtAmount": {
            "type": "number",
            "nullable": true,
            "description": "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."
          },
          "netAprAtAmount": {
            "type": "number",
            "nullable": true,
            "description": "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."
          },
          "netAprAtAmountBase": {
            "type": "number",
            "nullable": true,
            "description": "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."
          },
          "borrowDepthShort": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Debt-market rate-vs-amount borrow grid. Only when depth=true."
          },
          "supplyDepthLong": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Collateral-market rate-vs-amount supply grid. Only when depth=true."
          },
          "risk": {
            "type": "object",
            "description": "Per-dimension risk for the pair. No composite headline score — take the worst (highest) breakdown entry if you need one.",
            "properties": {
              "maxTokenScore": {
                "type": "integer",
                "nullable": true,
                "description": "Worse of the two sides' token risk scores."
              },
              "breakdown": {
                "type": "array",
                "description": "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\".",
                "items": {
                  "type": "object",
                  "properties": {
                    "category": {
                      "type": "string",
                      "example": "lender"
                    },
                    "score": {
                      "type": "integer",
                      "nullable": true,
                      "description": "Normalized risk score — lower is safer."
                    },
                    "label": {
                      "type": "string",
                      "enum": [
                        "low",
                        "medium",
                        "high",
                        "unknown"
                      ]
                    },
                    "curatorIds": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "type": "string"
                      },
                      "description": "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."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "LeveragePairsResponse": {
        "type": "object",
        "properties": {
          "start": {
            "type": "integer"
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeveragePair"
            },
            "description": "The result set for this response."
          }
        }
      },
      "OptimizerPairsResponse": {
        "type": "object",
        "properties": {
          "chainIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "EVM chain ids, as decimal strings. See the `ChainId` schema."
          },
          "collaterals": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "debts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "collateralAmount": {
            "type": "number"
          },
          "collateralAmountUsd": {
            "type": "number"
          },
          "debtAmount": {
            "type": "number"
          },
          "debtAmountUsd": {
            "type": "number"
          },
          "start": {
            "type": "integer"
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OptimizerPair"
            },
            "description": "The result set for this response."
          }
        }
      },
      "ComparableRateHorizon": {
        "type": "object",
        "description": "How the effective rate was arrived at — the caveats a UI must show next to a normalized number.",
        "properties": {
          "basis": {
            "type": "string",
            "enum": [
              "flat-forward",
              "early-exit",
              "held-to-maturity",
              "rolled"
            ],
            "description": "`flat-forward`: no maturity, today’s floating rate assumed to hold. `early-exit`: horizon shorter than the term, the venue’s exit rule applied. `held-to-maturity`: horizon matches the term (the clean case). `rolled`: horizon outlasts the term, a roll at today’s rate assumed."
          },
          "locked": {
            "type": "boolean",
            "description": "Is the rate contractually fixed for the WHOLE horizon? False for floating pools and for a fixed term that has to be rolled to cover the horizon."
          },
          "priceRisk": {
            "type": "boolean",
            "description": "Exiting early means unwinding on an order book at the then-current price (Midnight/Term), so the realized cost can land either side of the quote. Not priced in — flagged."
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Display-ready caveats, most important first."
          }
        }
      },
      "ComparableRateDepth": {
        "type": "object",
        "properties": {
          "fillable": {
            "type": "number",
            "nullable": true,
            "description": "Depth ceiling in token units of the priced leg — borrow liquidity for a pool, total book depth for an order book."
          },
          "capped": {
            "type": "boolean",
            "description": "The requested amount exceeds `fillable`: this venue cannot fund the position at that size, and the row is demoted below every non-capped one."
          },
          "liquidityUsd": {
            "type": "number",
            "nullable": true
          },
          "utilization": {
            "type": "number",
            "nullable": true,
            "description": "Market utilization, as a fraction between 0 and 1."
          }
        }
      },
      "ComparableRateAsset": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "EVM contract address, lowercase or checksummed hex."
          },
          "assetGroup": {
            "type": "string",
            "description": "Group of economically equivalent assets, e.g. all USDC variants."
          },
          "symbol": {
            "type": "string",
            "description": "Token symbol, e.g. `WETH`."
          },
          "decimals": {
            "type": "number",
            "nullable": true,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "logoUri": {
            "type": "string",
            "nullable": true,
            "description": "URL of the logo image."
          },
          "marketUid": {
            "type": "string",
            "description": "Market identifier, formatted `lender:chainId:address`."
          }
        }
      },
      "ComparableRate": {
        "type": "object",
        "description": "One comparable venue/term. Three rates are kept deliberately apart: `aprPct` is what the venue advertises (0 notional / top of book), `aprAtAmountPct` is that rate at the requested size, `effectiveAprPct` is the size-priced rate normalized to the requested horizon — and is what `rank` sorts on.",
        "properties": {
          "rank": {
            "type": "integer",
            "description": "1-based position in the ranking. `0` on the `reference` item."
          },
          "chainId": {
            "type": "string",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "description": "Raw lender key — stable, use it for keying and deeplinks. Per-market lenders (Morpho Blue, Silo, Euler) encode a hashed market id here, so it is NOT presentable."
          },
          "lenderName": {
            "type": "string",
            "description": "Display name from the lender registry, falling back to the raw key when none is registered. This is what a UI should render."
          },
          "lenderLogoUri": {
            "type": "string",
            "nullable": true
          },
          "marketUid": {
            "type": "string",
            "description": "The market the rate belongs to: the debt market for a borrow quote, the collateral market for a supply quote."
          },
          "marketName": {
            "type": "string",
            "nullable": true
          },
          "curatorName": {
            "type": "string",
            "nullable": true
          },
          "eMode": {
            "type": "string",
            "nullable": true
          },
          "rateType": {
            "type": "string",
            "enum": [
              "fixed",
              "float"
            ]
          },
          "rateModel": {
            "type": "string",
            "enum": [
              "variable",
              "lista",
              "midnight",
              "term",
              "exactly",
              "teller",
              "fixedTerm",
              "userSet",
              "zeroInterest"
            ],
            "description": "Which repayment rule priced this quote."
          },
          "aprPct": {
            "type": "number",
            "description": "Sticker rate, APR %. Includes intrinsic yield and reward APR (same composition as `borrowAprShort` / `depositAprLong`); a one-time origination fee is NOT in it — the horizon model amortizes that separately."
          },
          "aprAtAmountPct": {
            "type": "number",
            "nullable": true,
            "description": "The rate at the requested size. Null when no amount was supplied. A utilization pool re-prices its whole balance to the post-action rate; an order book fills cheapest-first, so this is the VWAP of the tiers consumed."
          },
          "rewardAprPct": {
            "type": "number",
            "nullable": true,
            "description": "Reward emissions folded into the headline (positive = subsidising a borrow). Large emissions can push a borrow rate NEGATIVE."
          },
          "aprExRewardsPct": {
            "type": "number",
            "nullable": true,
            "description": "The rate WITHOUT reward emissions — the structural, sustainable cost. Show it next to a reward-inflated headline; emissions are transient."
          },
          "effectiveAprPct": {
            "type": "number",
            "nullable": true,
            "description": "Size-priced rate normalized to `horizonDays`. The ranking number."
          },
          "costPct": {
            "type": "number",
            "nullable": true,
            "description": "Total cost over the horizon as a percent of principal."
          },
          "horizon": {
            "$ref": "#/components/schemas/ComparableRateHorizon"
          },
          "termId": {
            "type": "string",
            "nullable": true
          },
          "durationDays": {
            "type": "number",
            "nullable": true
          },
          "maturity": {
            "type": "number",
            "nullable": true,
            "description": "Calendar maturity, unix seconds. Null for rolling menus and variable pools."
          },
          "termDays": {
            "type": "number",
            "nullable": true,
            "description": "Remaining term in days for a position opened now."
          },
          "obtainable": {
            "type": "boolean",
            "description": "Can this rate be taken right now? False for a Term repo between auction rounds, whose rate card still quotes the last round’s clearing rate."
          },
          "obtainableReason": {
            "type": "string",
            "nullable": true
          },
          "quoteBasis": {
            "type": "string",
            "enum": [
              "live",
              "last-clearing"
            ],
            "description": "`last-clearing` marks a historical print, not an obtainable quote — never render it as an actionable rate."
          },
          "depth": {
            "$ref": "#/components/schemas/ComparableRateDepth"
          },
          "collateral": {
            "$ref": "#/components/schemas/ComparableRateAsset"
          },
          "debt": {
            "$ref": "#/components/schemas/ComparableRateAsset"
          },
          "maxLeverage": {
            "type": "number",
            "nullable": true,
            "description": "Highest leverage multiple reachable in this market."
          },
          "ltv": {
            "type": "number",
            "nullable": true,
            "description": "Loan-to-value ratio, as a fraction between 0 and 1."
          },
          "risk": {
            "type": "object",
            "properties": {
              "configScore": {
                "type": "number",
                "nullable": true
              },
              "maxTokenScore": {
                "type": "number",
                "nullable": true
              }
            }
          }
        }
      },
      "ComparableRatesResponse": {
        "type": "object",
        "properties": {
          "side": {
            "type": "string",
            "enum": [
              "borrow",
              "supply"
            ]
          },
          "horizonDays": {
            "type": "number"
          },
          "amount": {
            "type": "number"
          },
          "amountUsd": {
            "type": "number"
          },
          "chainIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "EVM chain ids, as decimal strings. See the `ChainId` schema."
          },
          "scanned": {
            "type": "integer",
            "description": "Pair rows considered before ranking."
          },
          "truncated": {
            "type": "boolean",
            "description": "The candidate guard cap bound, so ranking saw only the deepest rows — narrow the filter. Never a silent trim."
          },
          "available": {
            "type": "integer",
            "description": "Distinct comparables that existed before `limit` was applied."
          },
          "liquidityFloorUsd": {
            "type": "number",
            "description": "Venues below this USD depth were dropped as not comparable (0 = no floor applied)."
          },
          "droppedIlliquid": {
            "type": "integer",
            "description": "How many venues the depth band removed. An opinionated filter must never be silent — surface this rather than implying nothing else exists."
          },
          "droppedStale": {
            "type": "integer",
            "description": "Venues excluded because their market data is older than `staleMaxHours` — an ingest lag, not an absent lender. Non-zero is the difference between \"no one else offers this pair\" and \"we cannot currently see who does\". `includeStale=true` ranks them anyway."
          },
          "staleMaxHours": {
            "type": "number",
            "description": "The freshness window `droppedStale` was measured against."
          },
          "collateralBasis": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The single collateral group each chain's rows were compared against when the caller pinned none, e.g. `{\"1\":\"ETH\"}`. Empty when a collateral was supplied, or on the supply side."
          },
          "reference": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparableRate"
              }
            ],
            "nullable": true,
            "description": "The venue the caller is already on (`referenceMarketUid`), pulled out of `items` so the UI can render \"you: X% · best: Y%\"."
          },
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComparableRate"
            },
            "description": "The result set for this response."
          }
        }
      },
      "SparklineRequest": {
        "type": "object",
        "required": [
          "currencies",
          "quotes"
        ],
        "properties": {
          "currencies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Currency identifiers. Use shorthand (\"usd\", \"eth\") or \"{chainId}-{address}\" format."
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Quote identifiers (same format as currencies)"
          },
          "windowHours": {
            "type": "number",
            "default": 24,
            "description": "Lookback window in hours"
          }
        }
      },
      "SparklinePoint": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "description": "Price ratio (currency / quote)"
          },
          "time": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Sparkline": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string"
          },
          "quote": {
            "type": "string"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SparklinePoint"
            },
            "description": "Informational payload. `null` when the endpoint only builds calldata."
          }
        }
      },
      "SparklineResponse": {
        "type": "object",
        "properties": {
          "windowHours": {
            "type": "number"
          },
          "count": {
            "type": "integer",
            "description": "Number of non-empty sparkline pairs"
          },
          "result": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Sparkline"
            }
          }
        }
      },
      "MetaLendingCompleteResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of entries in `items`."
          },
          "items": {
            "type": "object",
            "additionalProperties": true,
            "description": "The result set for this response."
          }
        }
      },
      "UserPositionResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LenderDataEntry"
            },
            "description": "Flat array of lender entries sorted by net worth (descending). Each entry fuses position data with aggregated summary metrics."
          },
          "summary": {
            "$ref": "#/components/schemas/PortfolioSummaryResponse"
          },
          "partial": {
            "type": "boolean",
            "description": "Present and true when at least one lender could not be read in full (RPC error or reverted call). Totals are then a lower bound — a lender whose reads all failed is omitted rather than reported as an empty position."
          },
          "incompleteLenders": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present only when `partial` is set: the `chainId:lender` pairs whose on-chain reads (partly) failed.",
            "example": [
              "1:AAVE_V3",
              "1:COMPOUND_V3_USDC"
            ]
          }
        },
        "description": "User lending positions as a flat array with portfolio summary and per-chain breakdowns."
      },
      "LenderDataEntry": {
        "type": "object",
        "required": [
          "lender",
          "chainId",
          "account",
          "data",
          "balanceData",
          "aprData"
        ],
        "properties": {
          "lender": {
            "type": "string",
            "description": "Lender identifier",
            "example": "AAVE_V3"
          },
          "chainId": {
            "type": "string",
            "description": "Chain ID",
            "example": "1"
          },
          "account": {
            "type": "string",
            "description": "User account address",
            "example": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserSubAccount"
            },
            "description": "Sub-account position data"
          },
          "balanceData": {
            "$ref": "#/components/schemas/SummaryBalanceData"
          },
          "aprData": {
            "$ref": "#/components/schemas/SummaryAprData"
          },
          "leverage": {
            "type": "number",
            "description": "Leverage ratio (deposits / nav)",
            "example": 2
          }
        },
        "description": "Fused lender entry combining sub-account position data with aggregated summary metrics."
      },
      "UserSubAccount": {
        "type": "object",
        "required": [
          "accountId",
          "balanceData",
          "aprData",
          "positions",
          "userConfig"
        ],
        "properties": {
          "accountId": {
            "type": "string",
            "description": "Sub-account identifier (e.g., \"0\" for default, NFT ID for Init)",
            "example": "0"
          },
          "health": {
            "type": "number",
            "nullable": true,
            "description": "Health factor (null if no debt). Values > 1 are healthy, < 1 at risk of liquidation.",
            "example": 1.85
          },
          "borrowCapacityUSD": {
            "type": "number",
            "description": "Total USD borrowable while maintaining health >= 1",
            "example": 3000
          },
          "balanceData": {
            "$ref": "#/components/schemas/BalanceData"
          },
          "aprData": {
            "$ref": "#/components/schemas/AprData"
          },
          "positions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LendingPosition"
            },
            "description": "Individual asset positions in this sub-account"
          },
          "userConfig": {
            "$ref": "#/components/schemas/UserConfig"
          }
        },
        "description": "Position data for a single sub-account within a lender."
      },
      "BalanceData": {
        "type": "object",
        "properties": {
          "deposits": {
            "type": "number",
            "description": "Total deposits in USD",
            "example": 10000.5
          },
          "debt": {
            "type": "number",
            "description": "Total debt in USD",
            "example": 5000.25
          },
          "adjustedDebt": {
            "type": "number",
            "description": "Debt adjusted for borrow factors",
            "example": 5500
          },
          "collateral": {
            "type": "number",
            "description": "Collateral value in USD",
            "example": 9000
          },
          "collateralAllActive": {
            "type": "number",
            "description": "Collateral if all assets were enabled",
            "example": 10000.5
          },
          "borrowDiscountedCollateral": {
            "type": "number",
            "description": "Collateral discounted by borrow factors",
            "example": 8000
          },
          "borrowDiscountedCollateralAllActive": {
            "type": "number",
            "description": "Discounted collateral if all enabled",
            "example": 9000
          },
          "nav": {
            "type": "number",
            "description": "Net asset value (deposits - debt)",
            "example": 5000.25
          },
          "deposits24h": {
            "type": "number",
            "description": "Deposits 24h ago (for change calculation)",
            "example": 9800
          },
          "debt24h": {
            "type": "number",
            "description": "Debt 24h ago",
            "example": 4900
          },
          "nav24h": {
            "type": "number",
            "description": "NAV 24h ago",
            "example": 4900
          },
          "rewards": {
            "type": "array",
            "nullable": true,
            "description": "Pending reward token claims. Each entry represents a single reward program.",
            "items": {
              "$ref": "#/components/schemas/UserRewardEntry"
            }
          }
        },
        "description": "Aggregated balance data for a sub-account."
      },
      "AprData": {
        "type": "object",
        "properties": {
          "apr": {
            "type": "number",
            "description": "Net APR (deposit - borrow)",
            "example": 2.5
          },
          "depositApr": {
            "type": "number",
            "description": "Weighted deposit APR",
            "example": 3.5
          },
          "borrowApr": {
            "type": "number",
            "description": "Weighted borrow APR",
            "example": 5.2
          },
          "rewardApr": {
            "type": "number",
            "description": "Total reward APR",
            "example": 1.2
          },
          "rewardDepositApr": {
            "type": "number",
            "description": "Reward APR on deposits",
            "example": 0.8
          },
          "rewardBorrowApr": {
            "type": "number",
            "description": "Reward APR on borrows",
            "example": 0.4
          },
          "intrinsicApr": {
            "type": "number",
            "description": "Intrinsic yield APR (e.g., stETH staking)",
            "example": 0
          },
          "intrinsicDepositApr": {
            "type": "number",
            "description": "Intrinsic yield APR portion from deposits",
            "example": 0
          },
          "intrinsicBorrowApr": {
            "type": "number",
            "description": "Intrinsic yield APR portion from borrows",
            "example": 0
          },
          "rewards": {
            "type": "object",
            "description": "Per-reward-token APR breakdown. Keys are reward token addresses.",
            "additionalProperties": {
              "$ref": "#/components/schemas/RewardAprBreakdown"
            }
          }
        },
        "description": "APR breakdown for a sub-account."
      },
      "LendingPosition": {
        "type": "object",
        "properties": {
          "marketUid": {
            "type": "string",
            "description": "Unique market identifier (format: `{lender}:{chainId}:{address}`)",
            "example": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
          },
          "deposits": {
            "type": "string",
            "description": "Deposit amount in token units (wei)",
            "example": "1000000000000000000"
          },
          "debt": {
            "type": "string",
            "description": "Variable debt in token units",
            "example": "0"
          },
          "debtStable": {
            "type": "string",
            "description": "Stable debt in token units",
            "example": "0"
          },
          "debtShares": {
            "type": "string",
            "description": "Debt share amount (protocol-specific, present when the protocol uses share-based accounting)",
            "example": "0"
          },
          "depositShares": {
            "type": "string",
            "description": "Deposit share amount (protocol-specific, present when the protocol uses share-based accounting)",
            "example": "0"
          },
          "depositsUSD": {
            "type": "number",
            "description": "Deposits in USD (market price)",
            "example": 2500
          },
          "debtUSD": {
            "type": "number",
            "description": "Variable debt in USD (market price)",
            "example": 0
          },
          "debtStableUSD": {
            "type": "number",
            "description": "Stable debt in USD (market price)",
            "example": 0
          },
          "depositsUSDOracle": {
            "type": "number",
            "description": "Deposits in USD using on-chain oracle price (used for risk/health calculations)",
            "example": 2510
          },
          "debtUSDOracle": {
            "type": "number",
            "description": "Variable debt in USD using on-chain oracle price",
            "example": 0
          },
          "debtStableUSDOracle": {
            "type": "number",
            "description": "Stable debt in USD using on-chain oracle price",
            "example": 0
          },
          "collateralEnabled": {
            "type": "boolean",
            "description": "Whether this asset is enabled as collateral",
            "example": true
          },
          "claimableRewards": {
            "type": "number",
            "description": "Claimable rewards in USD",
            "example": 0.5
          },
          "withdrawable": {
            "type": "string",
            "description": "Max tokens withdrawable while maintaining health >= 1. Equals full deposit balance if collateral is not enabled.",
            "example": "0.5"
          },
          "borrowable": {
            "type": "string",
            "description": "Max tokens borrowable against remaining credit line. Zero if borrowing is disabled, reserve is frozen, or debt is disabled for the active mode.",
            "example": "100"
          },
          "underlyingInfo": {
            "$ref": "#/components/schemas/MarketUnderlyingInfo",
            "description": "Underlying asset metadata, oracle price, and market prices for this position."
          },
          "loanId": {
            "type": "string",
            "nullable": true,
            "description": "Lista DAO brokered markets only: identifies a single fixed-term loan (the broker posId; the dynamic/flex position uses `type(uint128).max`). Present on per-loan breakdown rows; absent on the aggregate debt row and on the shared collateral row. Pass to `/v1/actions/lending/repay?loanId=…`.",
            "example": "450"
          },
          "term": {
            "$ref": "#/components/schemas/LoanTerm",
            "nullable": true,
            "description": "Lista DAO brokered markets only: the fixed-term detail for this loan (rate, maturity, accrued interest, early-repay penalty). Present only on per-loan breakdown rows."
          }
        },
        "description": "Position data for a single asset within a lending protocol.\n\nFor **Lista DAO fixed-term (brokered)** markets a single market expands into several rows sharing the same `marketUid`:\n- one **aggregate debt** row (no `term`/`loanId`) where `debt` = the dynamic/variable loan and `debtStable` = the sum of fixed loans — use this for totals & health;\n- one **shared collateral** row (`collateralEnabled = true`, no `loanId`) backing every loan;\n- one **per-loan** row per open loan, each carrying `loanId` and a `term`. These are a breakdown of the aggregate — do not sum them into totals on top of the aggregate row."
      },
      "UserConfig": {
        "type": "object",
        "properties": {
          "selectedMode": {
            "type": "string",
            "description": "Mode/config key (e.g. e-mode category or vault address)",
            "example": "0"
          },
          "id": {
            "type": "string",
            "description": "Config identifier",
            "example": "0"
          },
          "isWhitelisted": {
            "type": "boolean",
            "description": "Whether user is whitelisted (for permissioned markets)"
          }
        },
        "description": "User configuration for a sub-account."
      },
      "SummaryBalanceData": {
        "type": "object",
        "properties": {
          "deposits": {
            "type": "number",
            "description": "Total deposits in USD",
            "example": 10000.5
          },
          "debt": {
            "type": "number",
            "description": "Total debt in USD",
            "example": 5000.25
          },
          "collateral": {
            "type": "number",
            "description": "Collateral value in USD",
            "example": 9000
          },
          "collateralAllActive": {
            "type": "number",
            "description": "Collateral if all assets were enabled",
            "example": 10000.5
          },
          "nav": {
            "type": "number",
            "description": "Net asset value (deposits - debt)",
            "example": 5000.25
          },
          "deposits24h": {
            "type": "number",
            "description": "Deposits 24h ago",
            "example": 9800
          },
          "debt24h": {
            "type": "number",
            "description": "Debt 24h ago",
            "example": 4900
          },
          "nav24h": {
            "type": "number",
            "description": "NAV 24h ago",
            "example": 4900
          },
          "rewards": {
            "type": "array",
            "nullable": true,
            "description": "Pending reward token claims. Each entry represents a single reward program.",
            "items": {
              "$ref": "#/components/schemas/UserRewardEntry"
            }
          }
        },
        "description": "Summary-level balance data (without discounted/adjusted fields)."
      },
      "SummaryAprData": {
        "type": "object",
        "properties": {
          "apr": {
            "type": "number",
            "description": "Net APR (deposit - borrow)",
            "example": 2.5
          },
          "depositApr": {
            "type": "number",
            "description": "Weighted deposit APR",
            "example": 3.5
          },
          "borrowApr": {
            "type": "number",
            "description": "Weighted borrow APR",
            "example": 5.2
          },
          "rewardApr": {
            "type": "number",
            "description": "Total reward APR",
            "example": 1.2
          },
          "rewardDepositApr": {
            "type": "number",
            "description": "Reward APR on deposits",
            "example": 0.8
          },
          "rewardBorrowApr": {
            "type": "number",
            "description": "Reward APR on borrows",
            "example": 0.4
          },
          "intrinsicApr": {
            "type": "number",
            "description": "Intrinsic yield APR (e.g., stETH staking)",
            "example": 0
          },
          "intrinsicDepositApr": {
            "type": "number",
            "description": "Intrinsic yield APR portion from deposits",
            "example": 0
          },
          "intrinsicBorrowApr": {
            "type": "number",
            "description": "Intrinsic yield APR portion from borrows",
            "example": 0
          },
          "rewards": {
            "type": "object",
            "description": "Per-reward-token APR breakdown. Keys are reward token addresses.",
            "additionalProperties": {
              "$ref": "#/components/schemas/RewardAprBreakdown"
            }
          }
        },
        "description": "Summary-level APR breakdown."
      },
      "PortfolioTotals": {
        "type": "object",
        "properties": {
          "balanceData": {
            "$ref": "#/components/schemas/SummaryBalanceData"
          },
          "aprData": {
            "$ref": "#/components/schemas/SummaryAprData"
          },
          "leverage": {
            "type": "number",
            "description": "Overall leverage ratio (deposits / nav)",
            "example": 2
          },
          "activeLenders": {
            "type": "integer",
            "description": "Number of lenders with positions",
            "example": 3
          },
          "activeChains": {
            "type": "integer",
            "description": "Number of chains with positions",
            "example": 2
          }
        },
        "description": "Aggregated portfolio totals across all chains and lenders."
      },
      "PortfolioSummaryResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PortfolioTotals"
          }
        ],
        "type": "object",
        "properties": {
          "chains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChainSummary"
            },
            "description": "Per-chain totals. Per-lender data is fused into the top-level items array."
          }
        },
        "description": "Portfolio-wide totals with per-chain breakdowns. Per-lender summaries are fused into each LenderDataEntry in the items array."
      },
      "ChainSummary": {
        "type": "object",
        "properties": {
          "chainId": {
            "type": "string",
            "description": "Chain ID",
            "example": "1"
          },
          "totalDepositsUSD": {
            "type": "number",
            "description": "Total deposits on this chain in USD",
            "example": 20000
          },
          "totalDebtUSD": {
            "type": "number",
            "description": "Total debt on this chain in USD",
            "example": 10000
          },
          "netWorth": {
            "type": "number",
            "description": "Net worth on this chain",
            "example": 10000
          },
          "lenderCount": {
            "type": "integer",
            "description": "Number of active lenders on this chain",
            "example": 2
          }
        },
        "description": "Aggregated totals for a single chain."
      },
      "RpcCallItem": {
        "type": "object",
        "description": "A JSON-RPC call object to be executed against an EVM node.",
        "required": [
          "method",
          "params"
        ],
        "properties": {
          "method": {
            "type": "string",
            "description": "JSON-RPC method name",
            "example": "eth_call"
          },
          "params": {
            "type": "array",
            "description": "JSON-RPC parameters (call object and block tag)",
            "items": {}
          }
        }
      },
      "RpcCallResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "rpcCallId",
              "rpcCalls"
            ],
            "properties": {
              "rpcCallId": {
                "type": "string",
                "format": "uuid",
                "description": "Unique ID referencing the server-side cached context. Pass this to /parse together with the raw responses. Valid for 5 minutes."
              },
              "rpcCalls": {
                "type": "array",
                "description": "Ordered list of JSON-RPC calls to execute against the target chain RPC. Each call uses multicall3 aggregate3.",
                "items": {
                  "$ref": "#/components/schemas/RpcCallItem"
                }
              }
            },
            "description": "Informational payload. `null` when the endpoint only builds calldata."
          }
        }
      },
      "ParseUserDataRequest": {
        "type": "object",
        "required": [
          "rpcCallId",
          "rawResponses"
        ],
        "properties": {
          "rpcCallId": {
            "type": "string",
            "format": "uuid",
            "description": "The rpcCallId returned by /rpc-call."
          },
          "rawResponses": {
            "type": "array",
            "description": "Raw JSON-RPC response results in the same order as the rpcCalls array. Each entry is the hex-encoded result of the corresponding multicall3 aggregate3 call.",
            "items": {
              "type": "object",
              "description": "Raw JSON-RPC response object",
              "properties": {
                "result": {
                  "type": "string",
                  "description": "Hex-encoded result data"
                }
              }
            }
          }
        }
      },
      "ParseTokenBalancesRequest": {
        "type": "object",
        "required": [
          "rpcCallId",
          "rawResponses"
        ],
        "properties": {
          "rpcCallId": {
            "type": "string",
            "format": "uuid",
            "description": "The rpcCallId returned by /token/balances/rpc-call."
          },
          "rawResponses": {
            "type": "array",
            "description": "Array containing the raw hex-encoded result from the eth_call. Typically a single-element array.",
            "items": {
              "type": "string",
              "description": "Hex-encoded result string (0x-prefixed)"
            }
          }
        }
      },
      "TokenListResponse": {
        "type": "object",
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "count": {
            "type": "integer",
            "description": "Total number of tokens"
          },
          "tokens": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/TokenMeta"
            },
            "description": "Map of token address (lowercase) → token metadata"
          }
        }
      },
      "TokenMeta": {
        "type": "object",
        "properties": {
          "symbol": {
            "type": "string",
            "example": "USDC",
            "description": "Token symbol, e.g. `WETH`."
          },
          "name": {
            "type": "string",
            "example": "USD Coin",
            "description": "Human-readable display name."
          },
          "decimals": {
            "type": "integer",
            "example": 6,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "assetGroup": {
            "type": "string",
            "example": "USDC",
            "description": "Group of economically equivalent assets, e.g. all USDC variants."
          },
          "logoURI": {
            "type": "string",
            "description": "Optional logo URL"
          }
        }
      },
      "TokenBalance": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Token contract address (zeroAddress for native)",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
          },
          "symbol": {
            "type": "string",
            "example": "USDC",
            "description": "Token symbol, e.g. `WETH`."
          },
          "name": {
            "type": "string",
            "example": "USD Coin",
            "description": "Human-readable display name."
          },
          "decimals": {
            "type": "integer",
            "example": 6,
            "description": "Token decimals — divide raw amounts by `10 ** decimals`."
          },
          "balanceRaw": {
            "type": "string",
            "description": "Raw balance in smallest unit (wei)",
            "example": "1000000"
          },
          "balance": {
            "type": "string",
            "description": "Formatted balance as decimal string",
            "example": "1.0"
          },
          "priceUSD": {
            "type": "number",
            "description": "Per-unit USD price of the token",
            "example": 1
          },
          "balanceUSD": {
            "type": "number",
            "description": "Balance value in USD",
            "example": 1
          }
        }
      },
      "TokenPricesResponse": {
        "type": "object",
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "count": {
            "type": "integer",
            "description": "Number of resolved assets"
          },
          "items": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Map of lowercase address → USD price",
            "example": {
              "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": 1,
              "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": 3500.12
            }
          }
        }
      },
      "TokenBalancesResponse": {
        "type": "object",
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "account": {
            "type": "string",
            "description": "Lowercase account address",
            "example": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5"
          },
          "count": {
            "type": "integer",
            "description": "Number of balance entries"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TokenBalance"
            },
            "description": "The result set for this response."
          }
        }
      },
      "AvailableAsset": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Token contract address",
            "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
          },
          "chain_id": {
            "type": "integer",
            "example": 1,
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "symbol": {
            "type": "string",
            "example": "USDC",
            "description": "Token symbol, e.g. `WETH`."
          },
          "name": {
            "type": "string",
            "example": "USD Coin",
            "description": "Human-readable display name."
          }
        },
        "additionalProperties": true
      },
      "TokenAvailableResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of available assets"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailableAsset"
            },
            "description": "The result set for this response."
          }
        }
      },
      "NextAccountResponse": {
        "type": "object",
        "required": [
          "accountType",
          "nextAccountId",
          "activeAccountIds",
          "accountIdRange",
          "createHint"
        ],
        "properties": {
          "accountType": {
            "type": "string",
            "enum": [
              "SELECT",
              "AUTOGEN"
            ],
            "description": "SELECT — integrator picks an ID from the range (Euler V2). AUTOGEN — ID is generated on-chain; omit the param to create (Init Capital)."
          },
          "nextAccountId": {
            "type": "string",
            "description": "For SELECT: lowest unused account ID. For AUTOGEN: preview of the on-chain generated ID.",
            "example": "1"
          },
          "activeAccountIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Currently active account IDs for this owner. May be empty for AUTOGEN protocols.",
            "example": [
              "0",
              "3",
              "7"
            ]
          },
          "accountIdRange": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 2,
            "maxItems": 2,
            "description": "Inclusive [min, max] range of valid account IDs.",
            "example": [
              "0",
              "255"
            ]
          },
          "createHint": {
            "type": "string",
            "description": "Human-readable instructions for integrators on how to create a new sub-account."
          }
        }
      },
      "LenderIdsResponse": {
        "type": "array",
        "description": "Sorted list of supported lender protocol identifiers.",
        "items": {
          "type": "string"
        },
        "example": [
          "AAVE_V2",
          "AAVE_V3",
          "COMPOUND_V2",
          "COMPOUND_V3_USDC",
          "EULER_V2",
          "INIT",
          "LISTA",
          "MORPHO",
          "SPARK",
          "VENUS"
        ]
      },
      "MidnightMakeInputs": {
        "type": "object",
        "description": "Deterministic offer inputs. Returned verbatim by `GET /v1/actions/midnight/make`; POST them back **unchanged** to `/v1/actions/midnight/finalize` alongside the signature so the worker rebuilds the identical offer tree. Any tampering fails on-chain ratification.",
        "properties": {
          "chainId": {
            "type": "string",
            "example": "8453",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "description": "`MORPHO_MIDNIGHT_<id>` lender key.",
            "example": "MORPHO_MIDNIGHT_0xABC…"
          },
          "buy": {
            "type": "boolean",
            "description": "`true` = maker BUYS units (a **lend** offer / bid); `false` = maker SELLS units (a **borrow** offer / ask)."
          },
          "tick": {
            "type": "string",
            "description": "Order-book tick the APR snapped to."
          },
          "start": {
            "type": "string",
            "example": "0"
          },
          "expiry": {
            "type": "string",
            "description": "Offer expiry, unix seconds."
          },
          "maxAssets": {
            "type": "string",
            "description": "Maker-side size in loan-token units."
          },
          "maker": {
            "type": "string",
            "description": "Maker (offer owner) address."
          }
        }
      },
      "MidnightMakeResponse": {
        "type": "object",
        "description": "Everything the frontend needs to sign and publish a maker offer (step 1 of the make flow). `actions` is `null` — the publish transaction is produced by `/finalize` after signing.",
        "properties": {
          "typedData": {
            "type": "object",
            "additionalProperties": true,
            "description": "EIP-712 typed-data to sign with `wallet.signTypedData` (bigints serialized as strings — sign the response as-is)."
          },
          "inputs": {
            "$ref": "#/components/schemas/MidnightMakeInputs"
          },
          "authorization": {
            "type": "object",
            "description": "One-time `setIsAuthorized(ecrecoverRatifier, true)` transaction on the Midnight core. Send FIRST, only if the maker has not authorized the ratifier yet (read `isAuthorized` on-chain).",
            "properties": {
              "to": {
                "type": "string"
              },
              "data": {
                "type": "string",
                "description": "Informational payload. `null` when the endpoint only builds calldata."
              },
              "value": {
                "type": "string",
                "description": "Native-token value to send with the transaction, in wei."
              },
              "ratifier": {
                "type": "string"
              }
            }
          },
          "aprPctSnapped": {
            "type": "number",
            "description": "The exact APR (percent) after tick-snapping — what the offer will actually quote once posted.",
            "example": 3.49
          },
          "maturity": {
            "type": "number",
            "description": "Market maturity, unix seconds."
          }
        }
      },
      "MidnightFinalizeRequest": {
        "type": "object",
        "required": [
          "inputs",
          "signature"
        ],
        "description": "Body for `POST /v1/actions/midnight/finalize`: the `inputs` echoed from `/make` plus the maker’s EIP-712 signature over `typedData`.",
        "properties": {
          "inputs": {
            "$ref": "#/components/schemas/MidnightMakeInputs"
          },
          "signature": {
            "type": "string",
            "description": "Maker signature over `typedData` (0x hex)."
          }
        }
      },
      "TermOfferSubmission": {
        "type": "object",
        "description": "A sealed lend offer for a Term auction.",
        "required": [
          "offeror",
          "offerPriceHash",
          "amount"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "bytes32 — omit / zero for a new offer (the locker assigns it)."
          },
          "offeror": {
            "type": "string",
            "description": "Offer owner address."
          },
          "offerPriceHash": {
            "type": "string",
            "description": "bytes32 commitment = `keccak(price, nonce)`, computed client-side; revealed later."
          },
          "amount": {
            "type": "string",
            "description": "Offer size in purchase-token units (integer wei)."
          },
          "purchaseToken": {
            "type": "string",
            "description": "Optional; defaults to the repo's purchase token."
          }
        }
      },
      "TermBidSubmission": {
        "type": "object",
        "description": "A sealed borrow bid for a Term auction (escrows collateral).",
        "required": [
          "bidder",
          "bidPriceHash",
          "amount",
          "collateralAmounts",
          "collateralTokens"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "bytes32 — omit / zero for a new bid."
          },
          "bidder": {
            "type": "string",
            "description": "Bid owner address."
          },
          "bidPriceHash": {
            "type": "string",
            "description": "bytes32 commitment = `keccak(price, nonce)`, computed client-side."
          },
          "amount": {
            "type": "string",
            "description": "Borrow size in purchase-token units (integer wei)."
          },
          "collateralAmounts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Collateral amounts to escrow, aligned with `collateralTokens`."
          },
          "collateralTokens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Collateral token addresses."
          },
          "purchaseToken": {
            "type": "string",
            "description": "Optional; defaults to the repo's purchase token."
          }
        }
      },
      "TermOfferRequest": {
        "type": "object",
        "required": [
          "chainId",
          "lender",
          "submissions"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "example": "TERM_FINANCE_0xABC…",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "submissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TermOfferSubmission"
            }
          },
          "referral": {
            "type": "string",
            "description": "Optional referral address."
          }
        }
      },
      "TermBidRequest": {
        "type": "object",
        "required": [
          "chainId",
          "lender",
          "submissions"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "example": "TERM_FINANCE_0xABC…",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "submissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TermBidSubmission"
            }
          },
          "referral": {
            "type": "string",
            "description": "Optional referral address."
          }
        }
      },
      "TermRevealRequest": {
        "type": "object",
        "description": "Reveal previously-locked offers or bids (opens the sealed price + nonce).",
        "required": [
          "chainId",
          "lender",
          "ids",
          "prices",
          "nonces"
        ],
        "properties": {
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "lender": {
            "type": "string",
            "example": "TERM_FINANCE_0xABC…",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "bytes32 offer/bid ids."
          },
          "prices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Revealed prices (integer)."
          },
          "nonces": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Revealed nonces."
          }
        }
      },
      "UnifiedUserOrder": {
        "type": "object",
        "description": "One of a user's own order-book / auction orders, normalized across providers (Midnight maker offers, Term secondary listings, Term auction submissions). `cancel` is a self-describing action the UI can fire directly.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Provider order id — the cancel target (Midnight offer root / Term listingId / auction submission id)."
          },
          "lender": {
            "type": "string",
            "example": "TERM_FINANCE_0xABC…",
            "description": "Protocol identifier. See the `LenderId` schema."
          },
          "chainId": {
            "type": "string",
            "example": "1",
            "description": "EVM chain id, as a decimal string. See the `ChainId` schema."
          },
          "kind": {
            "type": "string",
            "enum": [
              "maker-offer",
              "listing",
              "auction-offer",
              "auction-bid"
            ],
            "description": "`maker-offer` (Midnight signed limit offer), `listing` (Term secondary repo-token listing), `auction-offer`/`auction-bid` (Term primary sealed-bid submission)."
          },
          "side": {
            "type": "string",
            "enum": [
              "lend",
              "borrow"
            ]
          },
          "amount": {
            "type": "string",
            "description": "Order size, loan-token base units."
          },
          "assets": {
            "type": "number",
            "nullable": true,
            "description": "Size decimal-scaled to loan-token assets, or null."
          },
          "aprPct": {
            "type": "number",
            "nullable": true,
            "description": "Annualized rate in percent, or null while sealed."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "sealed",
              "revealed",
              "filled",
              "closed"
            ],
            "description": "`open` = cancellable now (maker offer / listing); `sealed`/`revealed` = auction lifecycle; `filled` = assigned at clearing; `closed` = complete or cancelled."
          },
          "filledAmount": {
            "type": "string",
            "description": "Amount assigned at clearing (auctions), base units."
          },
          "maturity": {
            "type": "number",
            "description": "Market/repo maturity, unix seconds."
          },
          "expiry": {
            "type": "number",
            "description": "Maker-offer expiry, unix seconds (Midnight)."
          },
          "revealTime": {
            "type": "number",
            "description": "Auction reveal window opens, unix seconds (Term)."
          },
          "auctionEndTime": {
            "type": "number",
            "description": "Auction closes / clears, unix seconds (Term)."
          },
          "cancel": {
            "type": "object",
            "nullable": true,
            "description": "Self-describing cancel/unlock action — omitted when not cancellable. Fetch `path`+`query` to build the cancel transaction.",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "GET",
                  "POST"
                ]
              },
              "path": {
                "type": "string",
                "example": "/v1/actions/term/unlock-offers"
              },
              "query": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "UnifiedOrdersResponse": {
        "type": "object",
        "description": "A user's own orders across order-book / auction lenders.",
        "properties": {
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnifiedUserOrder"
            }
          }
        }
      },
      "LenderId": {
        "type": "string",
        "enum": [
          "AAVE_V3",
          "AAVE_V3_PRIME",
          "AAVE_V3_ETHER_FI",
          "AAVE_V3_HORIZON",
          "AAVE_V2",
          "AURELIUS",
          "LENDLE",
          "LENDLE_CMETH",
          "LENDLE_SUSDE",
          "LENDLE_PT_CMETH",
          "MERIDIAN",
          "TAKOTAKO",
          "TAKOTAKO_ETH",
          "HANA",
          "YLDR",
          "MAGSIN",
          "SPARK",
          "NEREUS",
          "KINZA",
          "GRANARY",
          "LORE",
          "LENDOS",
          "IRONCLAD",
          "MOLEND",
          "SEISMIC",
          "POLTER",
          "AGAVE",
          "MOOLA",
          "XLEND",
          "KLAP",
          "RHOMBUS",
          "RMM",
          "KLAYBANK",
          "SAKE",
          "SAKE_ASTAR",
          "LAYERBANK_V3",
          "COLEND",
          "COLEND_LSTBTC",
          "PAC",
          "VALAS",
          "HYPERLEND",
          "HYPURRFI",
          "HYPERYIELD",
          "MOONCAKE",
          "PHIAT",
          "RADIANT_V2",
          "FATHOM",
          "U235",
          "QUOKKA_LEND",
          "PRIME_FI",
          "PLOUTOS",
          "YEI",
          "YEI_SOLV",
          "NEVERLAND",
          "KONA_LEND",
          "EDEL",
          "VOLTAGE_LENDING",
          "AQUALOAN",
          "BETTER_BANK",
          "BETTER_BANK_ATROPA",
          "DTRINITY",
          "ZONA",
          "ZEROLEND",
          "ZEROLEND_STABLECOINS_RWA",
          "ZEROLEND_ETH_LRTS",
          "ZEROLEND_BTC_LRTS",
          "ZEROLEND_CROAK",
          "ZEROLEND_FOXY",
          "LENDLE_SUSDE_USDT",
          "LENDLE_METH_WETH",
          "LENDLE_METH_USDE",
          "LENDLE_CMETH_WETH",
          "LENDLE_CMETH_USDE",
          "LENDLE_CMETH_WMNT",
          "LENDLE_FBTC_WETH",
          "LENDLE_FBTC_USDE",
          "LENDLE_FBTC_WMNT",
          "LENDLE_WMNT_WETH",
          "LENDLE_WMNT_USDE",
          "AVALON",
          "AVALON_SOLVBTC",
          "AVALON_SWELLBTC",
          "AVALON_PUMPBTC",
          "AVALON_UNIBTC",
          "AVALON_EBTC_LBTC",
          "AVALON_USDA",
          "AVALON_SKAIA",
          "AVALON_LORENZO",
          "AVALON_INNOVATION",
          "AVALON_UBTC",
          "AVALON_OBTC",
          "AVALON_BEETS",
          "AVALON_UNIIOTX",
          "AVALON_BOB",
          "AVALON_STBTC",
          "AVALON_WBTC",
          "AVALON_LBTC",
          "AVALON_XAUM",
          "AVALON_LISTA",
          "AVALON_USDX",
          "COMPOUND_V2",
          "VENUS",
          "VENUS_ETH",
          "VENUS_BNB",
          "VENUS_BTC",
          "VENUS_MEME",
          "VENUS_DEFI",
          "VENUS_GAMEFI",
          "VENUS_STABLE",
          "VENUS_TRON",
          "VENUS_ETHENA",
          "VENUS_CURVE",
          "SEGMENT",
          "ENCLABS",
          "ENCLABS_LST",
          "ENCLABS_PT_USD",
          "ENCLABS_PT_ETH",
          "ENCLABS_SONIC_ECO",
          "TAKARA",
          "UNITUS",
          "BENQI",
          "BENQI_AVALANCHE_ECOSYSTEM",
          "KEOM",
          "OVIX",
          "MOONWELL",
          "LODESTAR",
          "ORBITER_ONE",
          "MENDI",
          "SUMER",
          "TECTONIC",
          "TECTONIC_VENO",
          "TECTONIC_DEFI",
          "KINETIC",
          "KINETIC_FXRP",
          "KINETIC_JOULE",
          "SHOEBILL",
          "DFORCE",
          "TENDER",
          "FLUX_FINANCE",
          "WE_PIGGY",
          "GAMMA",
          "CREAM_FINANCE",
          "CAPY_FI",
          "COMPOUND_V3_USDC",
          "COMPOUND_V3_USDT",
          "COMPOUND_V3_USDE",
          "COMPOUND_V3_USDBC",
          "COMPOUND_V3_USDCE",
          "COMPOUND_V3_USDS",
          "COMPOUND_V3_WETH",
          "COMPOUND_V3_WRON",
          "COMPOUND_V3_AERO",
          "COMPOUND_V3_WSTETH",
          "COMPOUND_V3_WBTC",
          "INIT",
          "MORPHO_BLUE",
          "LISTA_DAO",
          "MORPHO_MIDNIGHT",
          "TERM_FINANCE",
          "EXACTLY",
          "LIQUITY_V2",
          "USDAF",
          "FELIX",
          "NERITE",
          "QUILL",
          "ENOSYS_LOANS",
          "SONETA",
          "EBISU",
          "RIVER",
          "TELLER",
          "INVERSE",
          "SKY",
          "FRANKENCOIN",
          "USDD",
          "TERMMAX",
          "LLAMALEND",
          "RESUPPLY",
          "CURVANCE",
          "FRAXLEND",
          "FLUID",
          "GEARBOX_V3",
          "SILO_V2",
          "SILO_V3",
          "EULER_V2",
          "DOLOMITE",
          "SWAYLEND_USDC"
        ],
        "title": "LenderId",
        "example": "AAVE_V3",
        "description": "Canonical protocol identifier, used as the first segment of a `marketUid` and as the `lender` query parameter. Upper snake case. 186 values at the time of writing; call `GET /v1/data/lender-ids` for the current set."
      },
      "ChainId": {
        "type": "string",
        "enum": [
          "1",
          "10",
          "14",
          "25",
          "40",
          "50",
          "56",
          "100",
          "130",
          "137",
          "143",
          "146",
          "169",
          "196",
          "250",
          "324",
          "369",
          "988",
          "999",
          "1088",
          "1116",
          "1135",
          "1329",
          "1672",
          "1868",
          "2741",
          "2818",
          "4326",
          "4663",
          "5000",
          "8217",
          "8453",
          "9745",
          "34443",
          "42161",
          "42220",
          "43111",
          "43114",
          "57073",
          "59144",
          "60808",
          "80094",
          "81457",
          "98866",
          "167000",
          "534352",
          "747474"
        ],
        "title": "ChainId",
        "example": "1",
        "x-enumDescriptions": {
          "1": "Ethereum",
          "10": "OP",
          "14": "Flare",
          "25": "Cronos",
          "40": "Telos EVM",
          "50": "XDC",
          "56": "BNB",
          "100": "Gnosis",
          "130": "Unichain",
          "137": "Polygon",
          "143": "Monad",
          "146": "Sonic",
          "169": "Manta Pacific",
          "196": "X Layer",
          "250": "Fantom Opera",
          "324": "zkSync",
          "369": "PulseChain",
          "988": "Stable",
          "999": "HyperEVM",
          "1088": "Metis Andromeda",
          "1116": "Core",
          "1135": "Lisk",
          "1329": "Sei",
          "1672": "Pharos",
          "1868": "Soneium",
          "2741": "Abstract",
          "2818": "Morph",
          "4326": "MegaETH",
          "4663": "Robinhood",
          "5000": "Mantle",
          "8217": "Kaia",
          "8453": "Base",
          "9745": "Plasma",
          "34443": "Mode",
          "42161": "Arbitrum One",
          "42220": "Celo",
          "43111": "Hemi",
          "43114": "Avalanche",
          "57073": "Ink",
          "59144": "Linea",
          "60808": "BOB",
          "80094": "Berachain",
          "81457": "Blast",
          "98866": "Plume",
          "167000": "Taiko",
          "534352": "Scroll",
          "747474": "Katana"
        },
        "description": "EVM chain id, sent as a decimal **string**. 47 chains supported at the time of writing; call `GET /v1/data/chains` for the current set."
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Optional. Without a key, requests are limited to 10 per 15 minutes. Get your key from https://auth.1delta.io/"
      }
    }
  }
}