---
title: "Quote an N:N basket: N input tokens funding M output tokens in one atomic transaction"
method: POST
path: "/multi-quote"
---

# Quote an N:N basket: N input tokens funding M output tokens in one atomic transaction

`POST /multi-quote`

## Request

- Base URL: `https://swap.vurto.cc/v1`
- URL: `https://swap.vurto.cc/v1/multi-quote`
- Auth: none required

Not decomposable into separate POST /quote calls — the backend's waterfall allocation (which input finances which output) is the thing being computed, then each resulting slice is quoted through the same provider fan-out POST /quote uses. inputLegs[] is what you sell (tokenIn + amount|amountRaw, each). outputLegs[] is what you want back as outputPercent, an integer percent of the TOTAL basket value (not a fixed amount) — every outputLegs[].outputPercent in the request must sum to exactly 100. Up to 10 combined input+output legs; the waterfall never produces more than inputLegs.length + outputLegs.length - 1 real on-chain legs. CoW is never a candidate leg (an EIP-712 signature or a separately-settled ETH-flow order can't be one leg of one atomic transaction). Pass the signing wallet to receive a buildable basket quoteId; without it the response is indicative and has no handoff.

## Request body

- object
  - `wallet` string: Optional EVM signing address. Makes the basket quote executable and adds quoteId to the response.
  - `chainId` integer, required: The multi-swap router must be deployed on this chain or the request fails with 503 multi_swap_not_supported_on_chain.
  - `inputLegs` object[], required
    - `tokenIn` string, required: Address or symbol.
    - `amount` string: Human decimal amount. Use this OR amountRaw, not both.
    - `amountRaw` string: Raw integer string in tokenIn's smallest unit.
  - `outputLegs` object[], required
    - `tokenOut` string, required: Address or symbol.
    - `outputPercent` integer, required: Integer percent of the TOTAL basket value this leg receives. Every outputLegs[].outputPercent must sum to exactly 100.
    - `receiver` string: Optional: deliver this leg's output to a different address than the signing wallet.
  - `slippageBps` integer: Applied to every leg. Default 50.

## Response `200`

OK

- object
  - `requestId` string, uuid
  - `quoteId` string, uuid: Present only when the request included wallet. Pass it to POST /multi-quote/build.
  - `chainId` integer
  - `wallet` string
  - `pivot` string: USDC address on this chain — the internal reference asset the waterfall allocation prices every input/output against. Not part of execution.
  - `legs` MultiQuoteLeg[]: Every leg the allocation produced and successfully quoted — this is what POST /multi-quote/build executes.
    - `legIndex` integer: Position in the basket's flattened leg list, 0-based.
    - `inputLegIndex` integer: Index into the request's inputLegs[] this leg draws from.
    - `outputLegIndex` integer: Index into the request's outputLegs[] this leg funds.
    - `tokenIn` string
    - `tokenOut` string
    - `tokenInDecimals` integer
    - `tokenOutDecimals` integer
    - `amountIn` string: Raw integer string: this leg's share of the input token after allocation, not the full inputLegs[] amount.
    - `receiver` string
    - `quote` NormalizedQuote
      - `id` string: Opaque quote id. Pass as `quoteId` to POST /swap or POST /orders.
      - `provider` 'velora' | 'kyberswap' | 'uniswap' | 'aerodrome' | 'sushi' | 'pancake' | 'quickswap' | 'composto' | '1inch' | 'cowswap': Full provider list varies by chain; see GET /chains and provider health.
      - `venues` object[]: The exchanges the route crosses, in order, present only when there is more than one. A `composto` quote carries two entries; a single-venue route omits the field entirely.
        - `provider` string
        - `tokenIn` string
        - `tokenOut` string
      - `providerLabel` string
      - `chainId` integer
      - `tokenIn` string
      - `tokenOut` string
      - `amountIn` string: Raw integer string, in the input token's smallest unit.
      - `amountOut` string: Raw integer string, the provider's expected output.
      - `minimumAmountOut` string: Raw integer string, the worst acceptable output after slippage. This is what the on-chain call enforces.
      - `amountOutUsd` number, nullable
      - `gasUsd` number, nullable
      - `netValueUsd` number, nullable: Output value minus estimated gas minus platform fee. This is the ranking key, not amountOut.
      - `priceImpact` number, nullable
      - `platformFeeBps` integer
      - `platformFeeAmount` string
      - `confidence` integer: 0-100, lower when the provider's own health has degraded recently.
      - `latencyMs` integer
      - `quotedAt` integer: Unix ms.
      - `expiresAt` integer: Unix ms. The provider's own quote TTL, informational — POST /swap always re-quotes fresh before building.
      - `quoteBlock` integer, nullable
      - `mevProtection` 'full' | 'partial' | 'public' | 'unknown'
      - `supportsReceiver` boolean: Whether this provider can deliver the output to a `receiver` different from the wallet that signs.
      - `receiver` string: Present only when the request set a `receiver` different from the signing wallet.
      - `approvalTarget` string, nullable: The spender the approve step of the build will grant the allowance to, so pre-approving this address is safe. It is the same address as `steps[].spender` and `approval.spender` for the same provider. Never absent when an allowance is needed. `null` when there is nothing to approve: native input token, or a CoW order selling the native asset. The Vurto router appears here only when it sits in the call path (a direct pool route where the Vurto fee is charged); on a direct pool route with no fee this is the DEX router itself. If the fee flips between quote and build the build refuses with `approval_target_changed` instead of approving another contract.
      - `route` RouteLeg[]
        - `exchange` string
        - `pool` string
        - `tokenIn` string
        - `tokenOut` string
        - `shareBps` integer: Share of the input routed through this leg, in basis points, for split routes.
      - `badges` string[]: Highlight codes, e.g. best_price, lowest_gas.
      - `warnings` QuoteNotice[]
        - `code` string: Stable code; translate client-side, don't display raw.
        - `vars` object
      - `executionKind` 'transaction' | 'order' | 'onchain_order': Only present on quotes returned from POST /quote. 'transaction': send `steps[].tx`. 'order': sign EIP-712 off-chain, no transaction. 'onchain_order': CoW ETH-flow, a real transaction that only registers the order.
      - `estimatedGas` integer: Gas in UNITS for this route, from our own model, present only when the USD figure also came from it. An integrator ranks in units against the gasPrice it read itself; without this it treats the route as if it cost no gas, which is an advantage by omission.
    - `netAmountOutEstimate` string: Display estimate only: quote.amountOut minus VurtoSwapRouter's 0.03% multi-leg fee. Not the enforced floor — quote.minimumAmountOut is what the on-chain call requires.
  - `failures` object[]: A partial basket is possible and reported here, never silently dropped.
    - `legIndex` integer
    - `code` string
  - `indicative` boolean
  - `expiresAt` integer: Unix ms for the shortest-lived leg quote.
  - `refreshedAt` integer

## Other responses

- `400`: invalid_chain_id | invalid_input_legs | invalid_output_legs | too_many_legs | invalid_output_percent | token_required | invalid_amount | amount_required | zero_value_input
- `409`: ambiguous_token — details.candidates has every match
- `502`: no_routes — no leg found a composable route; details.failures lists why | pivot_pricing_failed
- `503`: multi_swap_not_supported_on_chain | multi_swap_pivot_unavailable

---

[API](https://skmtc.dev/vurto/apis/vurto-swap-public-api.md) · [All operations](https://skmtc.dev/vurto/apis/vurto-swap-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/vurto/apis/vurto-swap-public-api/revisions/423be3a193b5?raw)
