Skip to main content
POST
Python (SDK)

Authorizations

x-api-key
string
header
required

Your Compass API Key. Get your key here.

Body

application/json

Unwind a leveraged loop: repeatedly withdraw collateral, swap it back to the borrow token at a guaranteed minimum output, and repay — all in ONE atomic transaction from the Credit Account.

owner
string
default:0x0E407CdeBD8e078E6966ef6740540d25F5897082
required

The address that owns the Credit Account.

Example:

"0x0E407CdeBD8e078E6966ef6740540d25F5897082"

chain
enum<string>
default:ethereum
required

Blockchain network. Not every protocol is deployed on every chain — see the protocol field — and a chain with no credit venue at all returns a 422 naming the chains that do.

Available options:
arbitrum,
base,
bsc,
ethereum,
hyperevm,
tempo
Example:

"ethereum"

collateral_token
string
default:WETH
required

Token supplied as collateral in the loop being unwound. For MORPHO it must be the market's collateral token.

Examples:

"wstETH"

"WETH"

borrow_token
string
default:USDC
required

Token borrowed in the loop; withdrawn collateral is swapped back to it and used to repay. For MORPHO it must be the market's loan token.

Examples:

"WETH"

"USDC"

protocol
enum<string>
default:AAVE

Lending protocol to unwind: AAVE, MORPHO, or EULER. On chain=hyperevm, AAVE is Hyperlend and MORPHO is Felix; EULER is not deployed there.

Available options:
AAVE,
EULER,
MORPHO
Example:

"AAVE"

market_id
string | null

Morpho only: the bytes32 market id (from /v2/credit/morpho_markets). Required when protocol=MORPHO.

collateral_vault
string | null

Euler only: the EVK vault the loop's collateral is in. Required when protocol=EULER.

borrow_vault
string | null

Euler only: the EVK vault the loop borrowed from (the sub-account's controller). Required when protocol=EULER.

sub_account_id
integer
default:0

Euler only: the EVC sub-account (0-255) holding the looped position to unwind. 0 is the Credit Account itself.

Required range: 0 <= x <= 255
target_multiplier

Target leverage after the unwind. Omit (null) for a FULL unwind: the debt is cleared exactly — accrued interest included — and all pair collateral is withdrawn back to the Credit Account. 1 runs the same exact debt close but leaves the collateral supplied (earning). A value greater than 1 delevers the position to that multiplier. Must be below the position's current multiplier.

Required range: x >= 1
Example:

2

max_slippage_percent
default:0.5

Per-swap slippage tolerance in percent. Unwind dust is bounded by this per iteration, so tighter slippage means less dust.

Required range: 0 < x <= 10
Example:

0.3

allow_partial
boolean
default:false

If the target cannot be reached in one transaction, return the maximum-progress plan (preview.fully_unwound=false) instead of a 400. This can happen because every withdrawal is sized to keep the health factor at or above 1.02 at that step, so a position opened very close to its liquidation threshold runs out of headroom before the target is met. A second unloop call, now from a much lower leverage, finishes the job.

Example:

false

gas_sponsorship
boolean
default:false

If true, returns EIP-712 typed data for gas-sponsored execution instead of an unsigned transaction.

Example:

false

preview
boolean
default:false

If true, build a display estimate only — no single-use firm quote is ever spent. NOTE that this guarantees only that no firm quote was spent — it does not guarantee an absent transaction: on an unwind no firm provider covers, and under pricing=market, the call still falls through to the aggregator and returns a signable transaction. On a firm-covered unwind (pricing 'auto' or 'firm') the numbers are firm-INDICATIVE, priced off the firm provider's live maker levels; otherwise they are market-priced with slippage-bounded floors. Under pricing='firm' a preview no firm provider can serve returns the advisory alone (preview=null + firm_available). Set it on every parameter-exploration call and omit it only on the build the user is about to sign.

pricing
enum<string>
default:auto

Swap-leg routing policy. 'auto': firm quotes where a firm venue covers the pair, transparent fallback to the market aggregator otherwise. 'firm': never price on the market route — previews the firm venue cannot serve return the firm_available advisory alone (preview=null, zero aggregator calls), and executions fail with a typed error instead of silently substituting market pricing. 'market': never route through the firm venue; every leg is priced by the aggregator. max_slippage_percent applies on EVERY policy — unlike the loop, firm unwinds consume it to size the guaranteed withdraw/repay floors (the fills themselves are exact). 'firm' is incompatible with gas_sponsorship (sponsored unwinds force market routing).

Available options:
auto,
firm,
market

Response

Successful Response

The atomic unwind transaction plus its guaranteed-floor preview.

preview
CreditUnloopPreview · object | null
required

Projected end state, computed on guaranteed swap floors. Null only on pricing='firm' preview responses whose unwind the firm venue cannot serve: no leg was priced on any venue, and the response carries the firm_available advisory alone.

transaction
UnsignedTransaction · object | null

Unsigned transaction for direct execution by the owner. Present when gas_sponsorship=false — except firm-priced previews (preview=true on a firm-priced build), which carry numbers only: the firm quotes are fetched at execution time, so there is no payload to sign yet.

Example:
eip_712
BatchedSafeOperationsResponse · object | null

EIP-712 typed data for gas-sponsored execution. Present when gas_sponsorship=true.

Example:
swap_provider
enum<string>
default:market

Identifies which route priced the swap leg(s): 'market' — a DEX aggregator (pool liquidity, slippage-bounded floors) — or 'firm' — quotes, one per swap leg, each partially filled at the leg's size. On preview=true responses 'firm' means the numbers are INDICATIVE, computed from live maker price levels without spending any quote; execution fetches the firm quotes at signing time. Always present, including on fallbacks. This is the authoritative firm-vs-market signal and clients do need to read it: pricing is only what was REQUESTED (under 'auto' a firm build can fall back to market transparently), and quote_expires_at is absent on every preview — so neither substitutes for this field.

Available options:
market,
firm
quote_expires_at
string<date-time> | null

Deadline of the firm swap quotes (the earliest across the unwind's swap legs) — sign and broadcast before it or the transaction reverts on-chain; refresh by re-calling this endpoint (discard the previous payload). Present only on executable firm-priced builds; null on previews (no quote is spent for a preview).

firm_available
boolean | null

Preview-only advisory: whether a firm-quote venue can serve this unwind's swap legs (estimated without spending any quote). Present only on preview=true responses; null otherwise. Computed on every policy — including pricing='market', whose preview numbers stay market-priced — so a client that opted out can keep the boundary visible.