{"openapi":"3.1.0","info":{"title":"Project 0 Agent API","version":"0.1.0","description":"Agent-facing REST surface for the Project 0 lending protocol on Solana. All transaction endpoints return UNSIGNED base64 transactions — the caller's wallet signs; this service never holds keys. The same capabilities are available over MCP at POST /mcp."},"servers":[{"url":"https://ai.0.xyz"}],"paths":{"/v1/banks":{"get":{"operationId":"getBanks","summary":"List lending banks with rates, sizes, weights, and e-mode","parameters":[{"name":"venue","in":"query","schema":{"type":"string"},"description":"P0 | Kamino | JupLend (case-insensitive)"},{"name":"mint","in":"query","schema":{"type":"string"},"description":"Token mint address (base58)"},{"name":"symbol","in":"query","schema":{"type":"string"},"description":"Token symbol, case-insensitive"},{"name":"include_inactive","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Banks list","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"_meta":{"type":"object","properties":{"cached_at":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Upstream snapshot time, unix ms — oldest of the composed rate/price sources. Names/symbols refresh on a slower (daily) cycle and do not count toward this age."},"source":{"type":"string","const":"monitor"},"max_age_sec":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Data is refreshed at most this often"}},"required":["cached_at","source","max_age_sec"],"additionalProperties":false},"bank_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"banks":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Bank address (base58). Pass this as `bank` to action tools/endpoints."},"symbol":{"type":"string","description":"Token symbol, e.g. \"USDC\""},"name":{"type":"string","description":"Token name, e.g. \"USD Coin\""},"venue":{"type":"string","description":"Lending venue backing this bank: \"P0\" | \"Kamino\" | \"JupLend\""},"asset_group":{"type":"string","description":"Asset bucket, e.g. \"stablecoins\", \"sol-lst\", \"governance\""},"mint":{"type":"string","description":"Token mint address (base58)"},"mint_decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Token decimals"},"price_usd":{"type":"string","description":"Oracle price in USD, decimal string. CAVEAT: for venue banks (Kamino/JupLend) this is currently the venue share-token (cToken) price, NOT the underlying token price — p0_get_positions and p0_get_wallet price the underlying, so the same mint can read differently here by the share exchange rate."},"asset_tag":{"type":"string","enum":["default","sol","staked","kamino","solend","juplend","unknown"],"description":"Asset class; \"staked\" banks are not actionable via this service in v1"},"risk_tier":{"type":"string","description":"\"Collateral\" (usable as collateral) or \"Isolated\""},"operational_state":{"type":"string","description":"\"Operational\" | \"Paused\" | \"ReduceOnly\" (variants like \"ReduceOnlyWithBorrowingPower\" exist) — only Operational banks accept new deposits/borrows"},"rates":{"type":"object","properties":{"total_deposit_apy_pct":{"type":"number","description":"THE deposit yield to quote, percent (4.2 = 4.2% APY): deposit_apy_pct + native_apy_pct + lending_emissions_apy_pct. Every component is already included — do not add them again."},"total_borrow_apy_pct":{"type":"number","description":"THE borrow cost to quote, percent: borrow_apy_pct + native_apy_pct - borrowing_emissions_apy_pct. Native yield counts as a cost when borrowing (a borrowed LST appreciates against the debt)."},"deposit_apy_pct":{"type":"number","description":"Component: the bank's own lending rate only, percent — EXCLUDES native yield and emissions, so it understates LST/yield-bearing deposits; quote total_deposit_apy_pct instead. For venue banks (Kamino/JupLend) this is the venue's own live rate model and moves with the venue's utilization."},"borrow_apy_pct":{"type":"number","description":"Component: the bank's own borrow rate only, percent — EXCLUDES native yield and emissions; quote total_borrow_apy_pct instead."},"native_apy_pct":{"type":"number","description":"Component: the token's own native yield, percent (LST staking yield, PT fixed yield, JLP/yield-bearing stablecoin yield), same value on every bank for the mint; 0 for plain tokens. Can be negative when the token lost value against its underlying. Reads 0 on asset_tag \"staked\" banks (validator APY is not reported here)."},"lending_emissions_apy_pct":{"type":"number","description":"Component: token-incentive APY paid to depositors, percent (0 when none)"},"borrowing_emissions_apy_pct":{"type":"number","description":"Component: token-incentive APY paid to borrowers, percent (0 when none) — reduces the borrow cost"},"utilization_pct":{"type":"number","description":"Utilization in percent (0-100). Describes the P0-side market — on venue banks it can read 0 while deposit_apy_pct is nonzero (yield is paid on the venue, not by P0 borrowers)."}},"required":["total_deposit_apy_pct","total_borrow_apy_pct","deposit_apy_pct","borrow_apy_pct","native_apy_pct","lending_emissions_apy_pct","borrowing_emissions_apy_pct","utilization_pct"],"additionalProperties":false,"description":"APYs in percent. The total_* fields are the full yield/cost; the rest are its components."},"size":{"type":"object","properties":{"deposits_usd":{"type":"string","description":"Total deposits, USD decimal string"},"borrows_usd":{"type":"string","description":"Total borrows, USD decimal string"},"available_liquidity_usd":{"type":"string","description":"Withdrawable/borrowable liquidity in the bank, USD decimal string"},"deposit_limit_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Deposit cap, USD decimal string; null = uncapped"},"borrow_limit_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Borrow cap, USD decimal string; null = uncapped"},"deposit_capacity_remaining_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Remaining room under the deposit cap, USD decimal string; null = uncapped"},"borrow_capacity_remaining_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Remaining room under the borrow cap, USD decimal string; null = uncapped"}},"required":["deposits_usd","borrows_usd","available_liquidity_usd","deposit_limit_usd","borrow_limit_usd","deposit_capacity_remaining_usd","borrow_capacity_remaining_usd"],"additionalProperties":false},"weights":{"type":"object","properties":{"asset_weight_init":{"type":"number","description":"Initial collateral weight (0-1); deposits count at this fraction for new borrows"},"asset_weight_maint":{"type":"number","description":"Maintenance collateral weight (0-1)"},"liability_weight_init":{"type":"number","description":"Initial liability weight (>=1)"},"liability_weight_maint":{"type":"number","description":"Maintenance liability weight (>=1)"}},"required":["asset_weight_init","asset_weight_maint","liability_weight_init","liability_weight_maint"],"additionalProperties":false},"emode":{"anyOf":[{"type":"object","properties":{"tag":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"This bank's e-mode tag. When this bank is used as COLLATERAL, this tag is what other banks' entries match via collateral_bank_emode_tag."},"entries":{"type":"array","items":{"type":"object","properties":{"collateral_bank_emode_tag":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"e-mode tag of the collateral bank this override applies to"},"asset_weight_init":{"type":"number","description":"Overridden initial collateral weight"},"asset_weight_maint":{"type":"number","description":"Overridden maintenance collateral weight"}},"required":["collateral_bank_emode_tag","asset_weight_init","asset_weight_maint"],"additionalProperties":false},"description":"Overrides that apply when BORROWING this bank: each entry names a collateral tag that gets the better weights. Empty = this bank grants no overrides as a borrow, but its tag may still unlock overrides on banks you borrow against it."}},"required":["tag","entries"],"additionalProperties":false},{"type":"null"}],"description":"E-mode weight overrides. Entries live on the borrow-side bank; a collateral-only bank (e.g. PT tokens) shows its tag with empty entries — look up the overrides on the bank you intend to borrow. null = no e-mode at all."},"positions":{"type":"object","properties":{"lenders":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open lending positions"},"borrowers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open borrowing positions"}},"required":["lenders","borrowers"],"additionalProperties":false}},"required":["address","symbol","name","venue","asset_group","mint","mint_decimals","price_usd","asset_tag","risk_tier","operational_state","rates","size","weights","emode","positions"],"additionalProperties":false}}},"required":["_meta","bank_count","banks"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/strategies":{"get":{"operationId":"getStrategies","summary":"Ranked leveraged yield strategies, rate-arb and directional","parameters":[{"name":"group","in":"query","schema":{"type":"string"},"description":"stablecoins | sol_lst | sol | eth | btc | jlp"},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100},"description":"Max strategies to return (default 20)"}],"responses":{"200":{"description":"Strategies, best first","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"_meta":{"type":"object","properties":{"cached_at":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Upstream computation time, unix ms"},"source":{"type":"string","const":"monitor"},"max_age_sec":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["cached_at","source","max_age_sec"],"additionalProperties":false},"strategy_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Total strategies matching the filter (before `limit` truncation)"},"strategies":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"\"stablecoins\" | \"sol_lst\" (rate-arb loops) or a directional asset: \"sol\" | \"eth\" | \"btc\" | \"jlp\""},"direction":{"anyOf":[{"type":"string","enum":["long","short"]},{"type":"null"}],"description":"Directional exposure; null for rate-arbitrage loop strategies"},"supply":{"type":"object","properties":{"bank":{"type":"string","description":"Bank address (base58) for this leg"},"symbol":{"type":"string"},"mint":{"type":"string"},"venue":{"type":"string","description":"Venue name matching /v1/banks: \"P0\" | \"Kamino\" | \"JupLend\""}},"required":["bank","symbol","mint","venue"],"additionalProperties":false,"description":"The asset deposited (the supply/collateral leg)"},"borrow":{"type":"object","properties":{"bank":{"type":"string","description":"Bank address (base58) for this leg"},"symbol":{"type":"string"},"mint":{"type":"string"},"venue":{"type":"string","description":"Venue name matching /v1/banks: \"P0\" | \"Kamino\" | \"JupLend\""}},"required":["bank","symbol","mint","venue"],"additionalProperties":false,"description":"The asset borrowed against it"},"rates":{"type":"object","properties":{"supply_apy_pct":{"type":"number","description":"Total supply-leg APY in percent = supply_lending_apy_pct + supply_native_apy_pct + supply_emissions_apy_pct"},"borrow_apy_pct":{"type":"number","description":"Total borrow-leg cost APY in percent = borrow_lending_apy_pct + borrow_native_apy_pct + borrow_emissions_apy_pct"},"supply_lending_apy_pct":{"type":"number","description":"Bank lending-rate portion of the supply APY (the venue's utilization-driven rate; derived, so ±0.01pp rounding)"},"borrow_lending_apy_pct":{"type":"number","description":"Bank borrow-rate portion of the borrow APY (derived, so ±0.01pp rounding)"},"supply_native_apy_pct":{"type":"number","description":"Native (e.g. staking) yield portion of the supply APY"},"borrow_native_apy_pct":{"type":"number","description":"Native yield portion of the borrow APY"},"supply_emissions_apy_pct":{"type":"number","description":"Emissions portion of the supply APY"},"borrow_emissions_apy_pct":{"type":"number","description":"Emissions portion of the borrow APY"},"net_apy_base_pct":{"type":"number","description":"Net APY at 1x (no leverage), percent"},"net_apy_at_max_leverage_pct":{"type":"number","description":"Net APY at max_leverage, percent"}},"required":["supply_apy_pct","borrow_apy_pct","supply_lending_apy_pct","borrow_lending_apy_pct","supply_native_apy_pct","borrow_native_apy_pct","supply_emissions_apy_pct","borrow_emissions_apy_pct","net_apy_base_pct","net_apy_at_max_leverage_pct"],"additionalProperties":false},"max_leverage":{"type":"number","description":"Maximum achievable leverage for this pair"},"available_strategy_size_usd":{"type":"string","description":"Remaining deployable capacity for this strategy, USD decimal string"},"capacity_is_estimate":{"type":"boolean","description":"true when capacity is a proxy estimate rather than an exact figure"},"binding_constraint":{"type":"string","description":"What limits capacity, e.g. \"deposit_cap\", \"borrow_cap\", \"rate_convergence\", \"liquidity\""},"emode_applied":{"type":"boolean","description":"Whether e-mode weight overrides apply to this pair"},"capacity_adjusted_score":{"type":"number","description":"Ranking score (higher = better yield weighted by deployable size) — the list is sorted by this. A NEGATIVE score means the strategy loses money at the scored leverage; entries with negative net APY at every leverage level are returned for completeness — never execute them expecting positive yield."}},"required":["group","direction","supply","borrow","rates","max_leverage","available_strategy_size_usd","capacity_is_estimate","binding_constraint","emode_applied","capacity_adjusted_score"],"additionalProperties":false}}},"required":["_meta","strategy_count","strategies"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/wallet/{address}":{"get":{"operationId":"getWallet","summary":"Wallet token holdings with USD values","parameters":[{"name":"address","in":"path","required":true,"description":"Wallet public key (base58)","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"}}],"responses":{"200":{"description":"Holdings, sorted by value","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"_meta":{"type":"object","properties":{"cached_at":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Read time, unix ms. Balances are fetched fresh from RPC; prices/metadata are at most 60s old."},"source":{"type":"string","const":"rpc"},"max_age_sec":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["cached_at","source","max_age_sec"],"additionalProperties":false},"wallet":{"type":"string","description":"The wallet address queried (base58)"},"total_value_usd":{"type":"string","description":"Value of the bank-oracle-priced holdings only, USD decimal string. When unpriced_token_count > 0 this is a PARTIAL total — the unpriced holdings' value is unknown, not zero."},"token_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unpriced_token_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many held tokens have no maintained price (excluded from total_value_usd)"},"tokens":{"type":"array","items":{"type":"object","properties":{"mint":{"type":"string","description":"Token mint (base58). Native SOL is reported under the wrapped-SOL mint with is_native_sol=true."},"symbol":{"type":"string","description":"From Project 0 bank metadata; \"\" for tokens not listed on the protocol"},"name":{"type":"string"},"is_native_sol":{"type":"boolean","description":"true for the native SOL balance entry (a wrapped-SOL token account shares the mint with false here)"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount_ui":{"type":"number","description":"Balance in UI token units (1.5 = 1.5 tokens)"},"amount_base_units":{"type":"string","description":"Exact balance in base units (integer string)"},"price_usd":{"type":"string","description":"Token price in USD, decimal string"},"value_usd":{"type":"string","description":"Position value in USD, decimal string"},"price_source":{"type":"string","enum":["bank_oracle","unpriced"],"description":"\"bank_oracle\" = mint has a Project 0 bank with a live oracle (any operational state), priced identically to p0_get_positions; \"unpriced\" = mint is not listed, or its only banks are wind-down banks with admin-fixed placeholder prices — the balance is real but its value is UNKNOWN, not zero"}},"required":["mint","symbol","name","is_native_sol","decimals","amount_ui","amount_base_units","price_usd","value_usd","price_source"],"additionalProperties":false},"description":"Sorted by value_usd descending. Tokens not listed on Project 0 appear with empty symbol/name and price_source \"unpriced\" — their value is unknown, not zero."}},"required":["_meta","wallet","total_value_usd","token_count","unpriced_token_count","tokens"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/account/{address}":{"get":{"operationId":"getAccount","summary":"Positions, health, and capacity (fresh on-chain compute)","parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address (returns all its accounts) or marginfi account address","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"}},{"name":"borrow_bank","in":"query","schema":{"type":"string"},"description":"Bank address to compute max borrow for"}],"responses":{"200":{"description":"Account read","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"_meta":{"type":"object","properties":{"computed_at":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Computation time, unix ms — account state is fetched fresh from RPC"},"source":{"type":"string","const":"rpc"},"oracle_max_age_sec":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Market context (banks/prices) is at most this old"}},"required":["computed_at","source","oracle_max_age_sec"],"additionalProperties":false},"query":{"type":"string","description":"The address that was queried"},"resolved_as":{"type":"string","enum":["account","authority"],"description":"\"account\" = query was a marginfi account address; \"authority\" = query was a wallet, all its accounts are returned"},"account_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"accounts":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Marginfi account address (base58). SAVE THIS — action tools take it as `account`."},"authority":{"type":"string","description":"The wallet that owns this account"},"health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false},"equity":{"type":"object","properties":{"total_assets_usd":{"type":"string","description":"Unweighted total assets, USD"},"total_liabilities_usd":{"type":"string"},"net_value_usd":{"type":"string","description":"Assets minus liabilities, USD"}},"required":["total_assets_usd","total_liabilities_usd","net_value_usd"],"additionalProperties":false},"net_apy_pct":{"type":"number","description":"Blended TOTAL APY on net value across all positions (native yield and emissions included), percent (negative = paying more than earning)"},"emode_active":{"type":"boolean","description":"Whether e-mode weight overrides are currently active"},"positions":{"type":"array","items":{"type":"object","properties":{"bank":{"type":"string","description":"Bank address (base58) — pass as `bank` to action tools"},"symbol":{"type":"string"},"mint":{"type":"string"},"venue":{"type":"string","description":"\"P0\" | \"Kamino\" | \"JupLend\""},"side":{"type":"string","enum":["lend","borrow"],"description":"lend = deposited collateral; borrow = debt"},"amount_ui":{"type":"number","description":"Position size in UI token units of the underlying"},"amount_usd":{"type":"string","description":"Position value in USD, decimal string"},"apy_pct":{"type":"number","description":"TOTAL current APY for this side, percent — earned for lend (lending_apy_pct + native_apy_pct + emissions_apy_pct), paid for borrow (lending_apy_pct + native_apy_pct - emissions_apy_pct). Components are in apy_breakdown; do not add them again."},"apy_breakdown":{"type":"object","properties":{"lending_apy_pct":{"type":"number","description":"The bank's own lending (lend side) or borrow (borrow side) rate, percent. For venue banks (Kamino/JupLend) this is the venue's own rate; 0 may mean the rate feed was temporarily unavailable."},"native_apy_pct":{"type":"number","description":"The token's own native yield (LST staking, PT fixed yield, ...), percent — earned when lending, a cost when borrowing"},"emissions_apy_pct":{"type":"number","description":"Token incentives for this side, percent — added to a lend APY, subtracted from a borrow cost"}},"required":["lending_apy_pct","native_apy_pct","emissions_apy_pct"],"additionalProperties":false,"description":"Components of apy_pct"},"max_withdraw_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"For lend positions: how much can be withdrawn right now (health-, liquidity-, and venue-capped — the same math the withdraw builder enforces). null for borrow positions."}},"required":["bank","symbol","mint","venue","side","amount_ui","amount_usd","apy_pct","apy_breakdown","max_withdraw_ui"],"additionalProperties":false}},"max_borrow":{"anyOf":[{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"type":"string"},"max_borrow_ui":{"type":"number","description":"Max borrowable now in UI units — same math the borrow builder enforces (0.92 volatility factor)"}},"required":["bank","symbol","max_borrow_ui"],"additionalProperties":false},{"type":"null"}],"description":"Populated only when a borrow_bank was passed in the request"}},"required":["address","authority","health","equity","net_apy_pct","emode_active","positions","max_borrow"],"additionalProperties":false},"description":"Empty when the wallet has no marginfi account yet — create one to start"}},"required":["_meta","query","resolved_as","account_count","accounts"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/health/{account}":{"get":{"operationId":"getHealth","summary":"Light health check for one account","parameters":[{"name":"account","in":"path","required":true,"description":"Marginfi account address, or a wallet owning exactly one account","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"}}],"responses":{"200":{"description":"Health summary"},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/activity/{authority}":{"get":{"operationId":"getActivity","summary":"Recent protocol actions for a wallet (indexer-lagged)","parameters":[{"name":"authority","in":"path","required":true,"description":"Wallet (authority) address","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100},"description":"Max entries per page (default 25)"},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"next_cursor from a previous page"}],"responses":{"200":{"description":"Activity list, newest first","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"_meta":{"type":"object","properties":{"source":{"type":"string","const":"monitor"},"fetched_at":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"When this page was fetched, unix ms — entries are indexer-lagged relative to this by up to a few minutes"},"note":{"type":"string","description":"Freshness caveat"}},"required":["source","fetched_at","note"],"additionalProperties":false},"authority":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` to fetch the next page; null = no more"},"activities":{"type":"array","items":{"type":"object","properties":{"signature":{"type":"string","description":"Transaction signature — verify on-chain or in an explorer"},"action":{"type":"string","description":"\"deposit\" | \"borrow\" | \"repay\" | \"withdraw\" | ..."},"account":{"type":"string","description":"Marginfi account address the action touched"},"timestamp":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Unix seconds"},"bank":{"type":"string"},"symbol":{"type":"string"},"mint":{"type":"string"},"amount_ui":{"type":"string","description":"Amount in UI token units, decimal string"},"amount_usd":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"USD value at the time, decimal string; null when unpriced"}},"required":["signature","action","account","timestamp","bank","symbol","mint","amount_ui","amount_usd"],"additionalProperties":false},"description":"Newest first"}},"required":["_meta","authority","count","next_cursor","activities"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/create-account":{"post":{"operationId":"buildCreateAccountTx","summary":"Build a create-account transaction","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The wallet that will own and sign for the new account"}},"required":["authority"],"additionalProperties":false}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/deposit":{"post":{"operationId":"buildDepositTx","summary":"Build a deposit (auto-creates an account for first-timers)","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The signing wallet (base58)"},"account":{"description":"Marginfi account; required if the wallet owns several","type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Bank address from p0_get_banks / GET /v1/banks"},"amount":{"type":"number","exclusiveMinimum":0,"description":"Amount in UI token units (1.5 = 1.5 tokens)"}},"required":["authority","bank","amount"],"additionalProperties":false}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/borrow":{"post":{"operationId":"buildBorrowTx","summary":"Build a borrow (guardrail-capped)","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The signing wallet (base58)"},"account":{"description":"Marginfi account; required if the wallet owns several","type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Bank address from p0_get_banks / GET /v1/banks"},"amount":{"type":"number","exclusiveMinimum":0,"description":"Amount in UI token units (1.5 = 1.5 tokens)"}},"required":["authority","bank","amount"],"additionalProperties":false}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/withdraw":{"post":{"operationId":"buildWithdrawTx","summary":"Build an unsigned withdrawal transaction","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"account":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"amount":{"description":"Required unless withdraw_all is true","type":"number","exclusiveMinimum":0},"withdraw_all":{"description":"Withdraw the entire position","type":"boolean"}},"required":["authority","bank"],"additionalProperties":false,"anyOf":[{"required":["amount"]},{"properties":{"withdraw_all":{"const":true}},"required":["withdraw_all"]}]}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/repay":{"post":{"operationId":"buildRepayTx","summary":"Build an unsigned debt repayment transaction","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"account":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"amount":{"description":"Required unless repay_all is true","type":"number","exclusiveMinimum":0},"repay_all":{"description":"Repay the entire debt (with a small buffer)","type":"boolean"}},"required":["authority","bank"],"additionalProperties":false,"anyOf":[{"required":["amount"]},{"properties":{"repay_all":{"const":true}},"required":["repay_all"]}]}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/loop":{"post":{"operationId":"buildLoopTx","summary":"Open a leveraged loop: borrow, swap, deposit in one flash loan","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","x-payment-required":true,"x-payment-info":{"protocols":["x402"],"pricingMode":"fixed","price":"$0.01"},"parameters":[{"name":"x-jupiter-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Jupiter API key for this build (overrides the service key). Never put keys in the body."},{"name":"x-titan-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Titan API key for this build (overrides the service key)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The signing wallet (base58)"},"account":{"description":"Existing marginfi account to add the position to; omit to auto-resolve","type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"create_new_account":{"description":"Create a fresh, isolated marginfi account for this position (recommended per strategy)","type":"boolean"},"deposit_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Collateral bank — a strategy's `supply.bank`"},"borrow_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Debt bank — a strategy's `borrow.bank` (P0 venue only)"},"amount":{"type":"number","exclusiveMinimum":0,"description":"Principal already in the wallet, in deposit-token UI units"},"leverage":{"type":"number","minimum":1,"maximum":100,"description":"Target leverage, e.g. 2 = 2x. Must be <= the strategy's max_leverage"},"slippage_bps":{"description":"Swap slippage tolerance in bps (default 100 = 1%, max 500), enforced on-chain via min-out","type":"integer","minimum":1,"maximum":500},"max_price_impact_bps":{"description":"Refuse the build if the route's expected loss vs oracle prices exceeds this, in bps (default 200 = 2%, max 1000)","type":"integer","minimum":1,"maximum":1000}},"required":["authority","deposit_bank","borrow_bank","amount","leverage"],"additionalProperties":false}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/close-position":{"post":{"operationId":"buildClosePositionTx","summary":"Unwind a loop: withdraw, swap, repay in one flash loan","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","x-payment-required":true,"x-payment-info":{"protocols":["x402"],"pricingMode":"fixed","price":"$0.01"},"parameters":[{"name":"x-jupiter-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Jupiter API key for this build (overrides the service key). Never put keys in the body."},{"name":"x-titan-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Titan API key for this build (overrides the service key)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"account":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"deposit_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Collateral bank to withdraw from (the loop's deposit_bank)"},"borrow_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Debt bank to repay (the loop's borrow_bank)"},"amount":{"description":"Debt to repay in borrow-token UI units; required unless repay_all","type":"number","exclusiveMinimum":0},"repay_all":{"description":"Repay the entire debt","type":"boolean"},"slippage_bps":{"description":"Swap slippage tolerance in bps (default 100 = 1%, max 500), enforced on-chain via min-out","type":"integer","minimum":1,"maximum":500},"max_price_impact_bps":{"description":"Refuse the build if the route's expected loss vs oracle prices exceeds this, in bps (default 200 = 2%, max 1000)","type":"integer","minimum":1,"maximum":1000}},"required":["authority","deposit_bank","borrow_bank"],"additionalProperties":false,"anyOf":[{"required":["amount"]},{"properties":{"repay_all":{"const":true}},"required":["repay_all"]}]}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/swap-collateral":{"post":{"operationId":"buildSwapCollateralTx","summary":"Swap collateral to another asset in one flash loan","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","x-payment-required":true,"x-payment-info":{"protocols":["x402"],"pricingMode":"fixed","price":"$0.01"},"parameters":[{"name":"x-jupiter-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Jupiter API key for this build (overrides the service key). Never put keys in the body."},{"name":"x-titan-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Titan API key for this build (overrides the service key)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The signing wallet (base58)"},"account":{"description":"Marginfi account holding the position; required if the wallet owns several","type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"amount":{"description":"How much of the from_bank position to move, in from-token UI units; required unless swap_all","type":"number","exclusiveMinimum":0},"swap_all":{"description":"Move the entire from_bank position","type":"boolean"},"slippage_bps":{"description":"Swap slippage tolerance in bps (default 100 = 1%, max 500), enforced on-chain via min-out","type":"integer","minimum":1,"maximum":500},"max_price_impact_bps":{"description":"Refuse the build if the route's expected loss vs oracle prices exceeds this, in bps (default 200 = 2%, max 1000)","type":"integer","minimum":1,"maximum":1000},"from_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Collateral bank to move out of (an existing lend position)"},"to_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Collateral bank to move into (any venue: P0, Kamino, JupLend)"}},"required":["authority","from_bank","to_bank"],"additionalProperties":false,"anyOf":[{"required":["amount"]},{"properties":{"swap_all":{"const":true}},"required":["swap_all"]}]}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/swap-debt":{"post":{"operationId":"buildSwapDebtTx","summary":"Swap debt to another asset in one flash loan","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","x-payment-required":true,"x-payment-info":{"protocols":["x402"],"pricingMode":"fixed","price":"$0.01"},"parameters":[{"name":"x-jupiter-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Jupiter API key for this build (overrides the service key). Never put keys in the body."},{"name":"x-titan-api-key","in":"header","required":false,"schema":{"type":"string"},"description":"Bring-your-own Titan API key for this build (overrides the service key)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authority":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The signing wallet (base58)"},"account":{"description":"Marginfi account holding the position; required if the wallet owns several","type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"},"amount":{"description":"How much of the from_bank position to move, in from-token UI units; required unless swap_all","type":"number","exclusiveMinimum":0},"swap_all":{"description":"Move the entire from_bank position","type":"boolean"},"slippage_bps":{"description":"Swap slippage tolerance in bps (default 100 = 1%, max 500), enforced on-chain via min-out","type":"integer","minimum":1,"maximum":500},"max_price_impact_bps":{"description":"Refuse the build if the route's expected loss vs oracle prices exceeds this, in bps (default 200 = 2%, max 1000)","type":"integer","minimum":1,"maximum":1000},"from_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Debt bank to move out of (an existing borrow position)"},"to_bank":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Debt bank to move into (P0 venue only)"}},"required":["authority","from_bank","to_bank"],"additionalProperties":false,"anyOf":[{"required":["amount"]},{"properties":{"swap_all":{"const":true}},"required":["swap_all"]}]}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string"},"authority":{"type":"string","description":"The wallet that must SIGN and submit (echoed)"},"account":{"type":"string","description":"The marginfi account acted on (or to be created). SAVE THIS for subsequent calls."},"bank":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Bank acted on (echoed); null for create_account"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Amount in UI token units (echoed)"},"submit":{"type":"string","enum":["sequential","bundle"],"description":"How to submit: \"sequential\" = sign and send in array order, waiting for each to confirm; \"bundle\" = ALL transactions must be signed with the returned blockhash and submitted together as ONE atomic Jito bundle (a Jito tip is already included — in one of the transactions, or as a trailing tip transaction) — sending them one by one will fail or leave a half-open position"},"leverage":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target leverage for loop actions; null otherwise"},"legs":{"anyOf":[{"type":"object","properties":{"deposit":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false},"borrow":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false}},"required":["deposit","borrow"],"additionalProperties":false},{"type":"null"}],"description":"Per-leg sizing for flash-loan actions (loop / close_position); null otherwise"},"swap":{"anyOf":[{"type":"object","properties":{"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Aggregator that won the route, e.g. \"JUPITER\" or \"TITAN\""},"in_mint":{"type":"string","description":"Token sold (base58 mint)"},"in_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"in_amount_ui":{"type":"number","description":"Amount sold, UI units of in_symbol"},"in_value_usd":{"type":"string","description":"Amount sold at oracle price, USD decimal string"},"out_mint":{"type":"string","description":"Token bought (base58 mint)"},"out_symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"out_amount_ui":{"type":"number","description":"Quoted amount bought, UI units of out_symbol"},"out_value_usd":{"type":"string","description":"Quoted amount bought at oracle price, USD decimal string"},"min_out_amount_ui":{"type":"number","description":"Guaranteed minimum bought — enforced on-chain; the transaction fails rather than deliver less"},"min_out_value_usd":{"type":"string","description":"min_out_amount_ui at oracle price, USD decimal string"},"slippage_bps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Slippage tolerance the route was built with (min_out = quoted out minus this)"},"oracle_price_impact_pct":{"type":"number","description":"EXPECTED cost of the route vs oracle prices, percent: (in_value_usd - out_value_usd) / in_value_usd. Positive = value lost, negative = better than oracle. Builds above max_price_impact_bps (default 2%) are refused with PRICE_IMPACT_TOO_HIGH; above 0.5% a warning is added."},"worst_case_loss_pct":{"type":"number","description":"WORST-CASE cost vs oracle prices, percent, if the swap fills at exactly min_out (expected cost + slippage)"},"price_impact_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price impact as reported by the aggregator, percent; null when it doesn't report one (Jupiter's builder never does) — use oracle_price_impact_pct, which is always set"}},"required":["provider","in_mint","in_symbol","in_amount_ui","in_value_usd","out_mint","out_symbol","out_amount_ui","out_value_usd","min_out_amount_ui","min_out_value_usd","slippage_bps","oracle_price_impact_pct","worst_case_loss_pct","price_impact_pct"],"additionalProperties":false,"description":"The swap inside the flash loan, valued at oracle prices with its expected and worst-case cost"},{"type":"null"}],"description":"Swap route inside the flash loan; null when no swap"},"bridge_mint":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when the flash loan had to route through a bridge token (two-hop); null otherwise"},"position_swap":{"anyOf":[{"type":"object","properties":{"from":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being reduced: collateral withdrawn (swap_collateral) or debt repaid (swap_debt)"},"to":{"type":"object","properties":{"bank":{"type":"string"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_ui":{"type":"number","description":"Amount in UI token units for this leg"}},"required":["bank","symbol","amount_ui"],"additionalProperties":false,"description":"The position being increased: expected collateral deposited (swap_collateral) or new debt borrowed (swap_debt) — swap.min_out_amount_ui bounds the worst case"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}],"description":"Per-side sizing for swap_collateral / swap_debt; null otherwise"},"transactions":{"type":"array","items":{"type":"object","properties":{"base64":{"type":"string","description":"UNSIGNED base64-encoded Solana v0 transaction — sign with the authority wallet and submit"},"type":{"type":"string","description":"Machine tag for this transaction's role, e.g. \"CRANK\", \"DEPOSIT\", \"FLASHLOAN\"; \"BUNDLE_TIP\" = the trailing Jito tip of a bundle build"},"label":{"type":"string","description":"Human-readable label"}},"required":["base64","type","label"],"additionalProperties":false},"description":"Sign and submit per `submit`: in array order (sequential) or as one atomic bundle"},"action_tx_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Index of the main action tx; earlier entries are oracle cranks that must land first"},"blockhash":{"type":"object","properties":{"value":{"type":"string"},"last_valid_block_height":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Transactions expire past this block height (~60s) — rebuild if expired"}},"required":["value","last_valid_block_height"],"additionalProperties":false},"simulation":{"type":"object","properties":{"success":{"type":"boolean","const":true,"description":"Builds are returned only when the preview simulation succeeded"},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false,"description":"The account's health AFTER this action lands"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking risk warnings — surface these to the user before signing"}},"required":["success","post_health","warnings"],"additionalProperties":false}},"required":["action","authority","account","bank","symbol","amount_ui","submit","leverage","legs","swap","bridge_mint","position_swap","transactions","action_tx_index","blockhash","simulation"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}},"/v1/tx/simulate":{"post":{"operationId":"simulateTxs","summary":"Simulate a transaction bundle, returning post-action health","description":"Returns UNSIGNED base64 v0 transactions — sign with the authority wallet and submit in array order. transactions[action_tx_index] is the main action; earlier entries are oracle cranks. The blockhash expires in ~60s; rebuild if expired. simulation.post_health is the account's health after the action. `submit` tells you how: \"sequential\" = one at a time in order; \"bundle\" = ALL transactions signed with the returned blockhash and submitted together as ONE atomic Jito bundle (the flash-loan builders — loop, close-position, swap-collateral, swap-debt — may require this).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"transactions":{"minItems":1,"maxItems":6,"type":"array","items":{"type":"string","minLength":1},"description":"Base64-encoded transactions to simulate as an atomic bundle, in order"},"account":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Marginfi account whose post-action health to compute"}},"required":["transactions","account"],"additionalProperties":false}}}},"responses":{"200":{"description":"Unsigned transaction envelope","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"post_health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","moderate","warning","critical"],"description":"healthy >0.5, moderate 0.1-0.5, warning 0.01-0.1, critical <=0.01; liquidation occurs at 0. Meaningful only when the account holds positions — an EMPTY account reads \"healthy\" with health_factor null."},"health_factor":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"(maint assets - maint liabilities) / maint assets; 1 = no debt, 0 = liquidatable. null = the account has no assets (empty account): there is nothing at risk, but do not compare null against the numeric bands."},"assets_usd_maint":{"type":"string","description":"Maintenance-weighted assets, USD decimal string"},"liabilities_usd_maint":{"type":"string"},"assets_usd_initial":{"type":"string","description":"Initial-weighted assets (governs new borrows)"},"liabilities_usd_initial":{"type":"string"},"free_collateral_usd":{"type":"string","description":"Initial-weighted borrowing power remaining, USD decimal string"}},"required":["status","health_factor","assets_usd_maint","liabilities_usd_maint","assets_usd_initial","liabilities_usd_initial","free_collateral_usd"],"additionalProperties":false},"warnings":{"type":"array","items":{"type":"string"}}},"required":["success","post_health","warnings"],"additionalProperties":false}}}},"400":{"description":"Invalid input (INVALID_ADDRESS, BANK_NOT_FOUND, ...)","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"string","description":"Prescriptive message: what broke and how to fix it"},"code":{"type":"string","enum":["INVALID_ADDRESS","BANK_NOT_FOUND","ACCOUNT_NOT_FOUND","ACCOUNT_AMBIGUOUS","NOT_FOUND","INSUFFICIENT_COLLATERAL","BORROW_LIMIT_EXCEEDED","LEVERAGE_EXCEEDED","SWAP_ROUTE_UNAVAILABLE","TX_TOO_LARGE","BRIDGE_CONFLICT","PRICE_IMPACT_TOO_HIGH","ORACLE_CRANK_FAILED","SIMULATION_FAILED","UPSTREAM_ERROR","RATE_LIMITED","INTERNAL_ERROR"]},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["error","code"],"additionalProperties":false}}}},"422":{"description":"Preview simulation or oracle crank failed — transactions withheld"},"429":{"description":"Rate limited; Retry-After header is set"},"502":{"description":"Upstream (monitor/app/RPC) unavailable"}}}}}}