Close margin position
GET/v1/actions/loop/close
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).
Response actions fields (when account is provided):
alternatives: DEX aggregator swap transactions sorted best-output-first. Pick one to execute.transactions: Empty for close operations (no setup needed).permissions: Lender withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first.
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).
Plain-text reference — GET /v1/actions/loop/close
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
route | query | auto, bundler3, native, composer, proxy | no | Which assembly to use, for lenders that have more than one. Morpho Blue only today. |
- (omitted) —
auto: prefer the protocol’s own tooling and fall back to the composer for anything it cannot express (a cross-market pair, a margin paid in a foreign asset, anEXACT_OUTPUTclose, a chain with no bundler3 or no swap adapter). bundler3/native— force Morpho’s bundler3. A request it cannot serve becomes an ERROR instead of silently falling back, which is what makes the route testable.composer/proxy— force the 1delta composer.
The default matters: the bundler3 route asks for setAuthorization(GeneralAdapter1),
Morpho’s own audited adapter, where the composer route asks for a standing grant on ours. |
| marketUidIn | query | string | yes | Market identifier for input side (lender:chainId:address). |
| marketUidOut | query | string | yes | Market identifier for output side (lender:chainId:address). |
| slippage | query | number | yes | Slippage tolerance (basis points) |
| account | query | string | no | Account address. Include to build transaction, omit for quote-only. |
| amount | query | string | yes | Amount in wei |
| tradeType | query | 0, 1 | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) |
| irModeOut | query | 0, 1, 2 | no | Interest rate mode for debt |
| usePendleMintRedeem | query | boolean | no | Use Pendle mint/redeem |
| isAll | query | boolean | no | Repay full debt |
| loanId | query | string | no | Lista DAO fixed-term (brokered) debt markets only. Identifies which loan the close repays
on the loop's repay leg: the loan's loanId (broker posId) from the user-positions response,
or the type(uint128).max sentinel (340282366920938463463374607431768211455) for the
flexible/dynamic position. Required when marketUidOut is a brokered market; ignored otherwise. |
| accountId | query | string | no | Account ID |
Response 200
| Field | Type | Description |
|---|---|---|
success | True | |
data | object | Informational data (quotes, simulation results, etc.) |
data.lender | string | Protocol identifier |
data.quotes | object[] | Candidate routes, best output first. Execute exactly one. |
data.quotes[].deltas | object | |
data.quotes[].deltas.aggregator | string | Aggregator source |
data.quotes[].deltas.tradeInput | number | Trade input amount |
data.quotes[].deltas.tradeOutput | number | Trade output amount |
data.quotes[].deltas.deltas | object | Balance deltas |
data.quotes[].rateImpact | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |
data.quotes[].rateImpact[].marketUid | string | Market identifier (format: lender:chainId:address) |
data.quotes[].rateImpact[].utilization | object | A current/projected pair for a single rate metric. |
data.quotes[].rateImpact[].borrowRate | object | A current/projected pair for a single rate metric. |
data.quotes[].rateImpact[].depositRate | object | A current/projected pair for a single rate metric. |
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. |
data.rateImpact[].marketUid | string | Market identifier (format: lender:chainId:address) |
data.rateImpact[].utilization | object | A current/projected pair for a single rate metric. |
data.rateImpact[].utilization.current | number | Current value |
data.rateImpact[].utilization.projected | number | Projected value after the action |
data.rateImpact[].borrowRate | object | A current/projected pair for a single rate metric. |
data.rateImpact[].borrowRate.current | number | Current value |
data.rateImpact[].borrowRate.projected | number | Projected value after the action |
data.rateImpact[].depositRate | object | A current/projected pair for a single rate metric. |
data.rateImpact[].depositRate.current | number | Current value |
data.rateImpact[].depositRate.projected | number | Projected value after the action |
data.lender | string | Protocol identifier |
data.quotes | object[] | Candidate routes, best output first. Execute exactly one. |
data.quotes[].deltas | object | |
data.quotes[].deltas.aggregator | string | Aggregator source |
data.quotes[].deltas.tradeInput | number | Trade input amount |
data.quotes[].deltas.tradeOutput | number | Trade output amount |
data.quotes[].deltas.deltas | object | Balance deltas |
data.quotes[].tx | object | An EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them. |
data.quotes[].tx.to | string | Target contract address |
data.quotes[].tx.data | string | Encoded calldata |
data.quotes[].tx.value | string | ETH value to send with the transaction |
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"). |
data.quotes[].rateImpact | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. |
data.quotes[].rateImpact[].marketUid | string | Market identifier (format: lender:chainId:address) |
data.quotes[].rateImpact[].utilization | object | A current/projected pair for a single rate metric. |
Example response
{
"success": true,
"data": {
"lender": "AAVE_V3",
"quotes": [
{
"deltas": {
"aggregator": "string",
"tradeInput": 1.0,
"tradeOutput": 1.0,
"deltas": {}
},
"rateImpact": [
{
"marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
"utilization": {
"current": 1.0,
"projected": 1.0
},
"borrowRate": {
"current": 1.0,
"projected": 1.0
},
"depositRate": {
"current": 1.0,
"projected": 1.0
}
}
]
}
],
"rateImpact": [
{
"marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
"utilization": {
"current": 1.0,
"projected": 1.0
},
"borrowRate": {
"current": 1.0,
"projected": 1.0
},
"depositRate": {
"current": 1.0,
"projected": 1.0
}
}
]
},
"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"
}
]
}
}
Request
Responses
- 200
- 400
- 429
- 500
- 502
Quote or full build response
Validation error
Rate limited. Unauthenticated callers share a per-IP budget; send an x-api-key header to lift it. Retry with exponential backoff.
Unexpected server error. Safe to retry with backoff.
An upstream data source or protocol origin failed (error.code is ORIGIN_FAILED). error.details carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400.