> For the complete documentation index, see [llms.txt](https://docs.swapkit.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.swapkit.dev/swapkit-api/v3-quote-request-a-swap-quote.md).

# /v3/quote - Request a swap quote

Obtain a quote before performing a swap.

**Method:** `POST`\
**URL:** `https://api.swapkit.dev/v3/quote`

The first step towards performing a swap is requesting a quote, which will compare the price offered by the different swap providers.

Quotes are cached for 5 minutes, and can be used to obtain swap transaction details.

***

### Request Schema

Here's a detailed description of the different parameters:

<table data-full-width="false"><thead><tr><th width="189.8828125">Parameter</th><th width="92">Type</th><th width="89">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>sellAsset</code></td><td><code>string</code></td><td>Yes</td><td>The asset being sold (e.g. <code>"ETH.ETH"</code>).</td></tr><tr><td><code>buyAsset</code></td><td><code>string</code></td><td>Yes</td><td>The asset being bought (e.g. <code>"BTC.BTC"</code>).</td></tr><tr><td><code>sellAmount</code></td><td><code>string</code></td><td>Yes</td><td>Amount in basic units (decimals separated with a dot).</td></tr><tr><td><code>sourceAddress</code></td><td><code>string</code></td><td>No</td><td>Blockchain address to send the asset from. Must be a valid address for the sell asset's chain<br><br>Note - This is optional. By providing here we can screen the address against our index of bad addresses. Full screen is done in the <code>/v3/swap</code> endpoint<br><br>Refunds go here unless you pass <code>refundAddress</code>. Must be an address the user controls and can receive at, <a href="/smart-contract-limitations-and-edge-cases.md#transaction-log-limit-2">not an exchange deposit address</a>.</td></tr><tr><td><code>destinationAddress</code></td><td><code>string</code></td><td>No</td><td>Recipient blockchain address to send the asset to. Must be a valid address for the buy asset's chain<br><br>Note - This is optional. By providing here we can screen the address against our index of bad addresses. Full screen is done in the <code>/v3/swap</code> endpoint</td></tr><tr><td><code>refundAddress</code></td><td><code>string</code></td><td>No</td><td>Where a failed swap refunds to, on the <strong>sell</strong> chain. Defaults to <code>sourceAddress</code> — set it when the sender can't receive funds, such as a send-only contract wallet. Not every route can honour it; see <a href="#refunding-to-a-different-address">Refunding to a different address</a>.</td></tr><tr><td><code>refundAddressSetting</code></td><td><code>string</code></td><td>No</td><td><code>WARNING</code> (default) or <code>STRICT</code> — what happens to a route that can't honour <code>refundAddress</code>. See <a href="#refunding-to-a-different-address">below</a>. Ignored when <code>refundAddress</code> is absent.</td></tr><tr><td><code>providers</code></td><td><code>array</code></td><td>No</td><td>Limits the possible liquidity providers. If omitted, all available providers are used.</td></tr><tr><td><code>slippage</code></td><td><code>number</code></td><td>No</td><td>Max slippage in percentage (5 = 5%).</td></tr><tr><td><code>affiliateFee</code></td><td>number</td><td>No</td><td>Affiliate fee override in basis points (0-1000, max 10%). Must be a positive integer. If it is not provided, the API key configured fee tiers are applied.</td></tr><tr><td><code>cfBoost</code></td><td><code>boolean</code></td><td>No</td><td>Enables Chainflip boost for better rates.</td></tr><tr><td><code>maxExecutionTime</code></td><td><code>number</code></td><td>No</td><td>Maximum execution time in seconds. Routes exceeding this time are filtered out.</td></tr><tr><td><code>quoteType</code></td><td><code>string</code></td><td>No</td><td><code>"EXACT_INPUT"</code> (default) or <code>"FLEX_INPUT"</code>. Controls how the provider treats the input amount. See <a href="#flex-input-quotes">Flex input quotes</a> below.</td></tr><tr><td><code>usePrivacyMode</code></td><td><code>boolean</code></td><td>No</td><td>Set to <code>true</code> to request a privacy-preserving swap, where the trade details aren't exposed publicly while the swap executes. Acts as a filter. <a href="#privacy-mode">See Privacy mode</a>. Default: <code>false</code>.</td></tr><tr><td><code>enableSweep</code></td><td><code>boolean</code></td><td>No</td><td>Set to true to enable sweeping wallet funds when the transaction would otherwise leave unspendable dust in the address. <strong>UTXO, TON and TRON only.</strong> EVM chains don't sweep — reserve too little and the send fails at broadcast, too much and the user silently sells less than they asked — so size your own reserve there. Default: <code>false</code></td></tr><tr><td><code>gasCheck</code></td><td><code>boolean</code></td><td>No</td><td>Set to true to check the wallet's native gas balance and warn when it can't cover the network fee. Opt-in, and applies to <strong>token sells</strong> only. The check runs at <code>/v3/swap</code>, which inherits this value unless it sets its own — no <code>insufficientGas</code> warning appears in the <code>/v3/quote</code> response. Default: <code>false</code>.</td></tr><tr><td><code>txHints</code></td><td><code>array</code></td><td>No</td><td>Only return routes your wallet can sign: <code>simpleTransfer</code> (transfer to a deposit address), <code>transferWithMemo</code> (transfer carrying a memo or OP_RETURN), or <code>contractCall</code> (calldata submitted to a contract). No match returns <code>404 noRoutesFound</code>.</td></tr></tbody></table>

**Note:** Asset names for `sellAsset` and `buyAsset` should follow the following nomenclature:

* Chain.Asset (e.g., `"BTC.BTC"` or `"ARB.ETH"`)
* Chain.Asset-ContractAddress (e.g., `"ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"`)

This is the `identifier` as provided in the [`/tokens`](/swapkit-api/tokens-list-and-search-supported-tokens.md) or [`/swapTo`](/swapkit-api/swapto-request-buy-swap-options.md) endpoints.

***

#### Flex input quotes

The optional `quoteType` parameter controls how the amount you send is treated by the swap provider.

<table><thead><tr><th width="238.34765625">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>EXACT_INPUT</code> (default)</td><td>The exact <code>sellAmount</code> is swapped. This is the standard behaviour and applies when <code>quoteType</code> is omitted.</td></tr><tr><td><code>FLEX_INPUT</code></td><td>Swaps whatever is actually deposited instead of requiring the exact <code>sellAmount</code>. Set it when your deposit amount isn't fixed at quote time.</td></tr></tbody></table>

By default a quote assumes you'll deposit the exact input amount you asked for. Flexible input relaxes that: the amount that actually arrives may differ from the quote, and the route settles on whatever it receives.

It applies in three cases:

* **Sending a full balance.** When the wallet sweeps its whole balance (when `enableSweep` is set), the exact amount isn't known until send time, so flexible input is applied automatically. EVM chains don't sweep — see `enableSweep` above.
* **Manual sends.** If the user signs and sends the transaction themselves and might deposit a slightly different amount than quoted, pass `quoteType: FLEX_INPUT` so the first leg tolerates the difference.
* **Multi-provider routes.** On any leg after the first, the input is the previous leg's output, which isn't known exactly ahead of time — so flexible input is turned on automatically for those legs.

When you pass `FLEX_INPUT`, only routes where every provider supports flexible input are returned — any route containing a provider that doesn't is dropped.

Flexible input is decided entirely at quote time. Both the behaviour and the route filtering happen at `/v3/quote`; it can't be set at `/swap`, which only executes the route you've already picked.

The providers that support FLEX\_INPUT are:

* `THORCHAIN_STREAMING`
* `MAYACHAIN_STREAMING`
* `CHAINFLIP`
* `CHAINFLIP_STREAMING`
* `NEAR`
* `FLASHNET`

#### Privacy mode

The optional `usePrivacyMode` parameter requests a privacy-preserving swap, where the trade details aren't exposed publicly while it executes. Off unless you ask for it. Today it's fulfilled through NEAR Intents' Confidential Intents, though the parameter describes the capability rather than any one provider's implementation.

It's a **filter, not a preference**: only routes where *every* provider supports a privacy mode are returned. A route whose second hop is public exposes the trade just as thoroughly as a fully public one, so partial privacy is treated as no privacy. `NEAR` is the only privacy-capable provider today, so requesting privacy narrows you to the pairs NEAR Intents covers.

{% hint style="warning" %}
Because it filters rather than falls back, `usePrivacyMode: true` can leave you with nothing on a pair that quotes fine without it — either `404 noRoutesFound`, or `200` with an empty `routes` array and a populated `providerErrors`. Decide up front whether you retry as a public quote or tell the user the pair isn't available privately; silently returning a public route is the wrong answer, since the user wouldn't know they hadn't got privacy.
{% endhint %}

Privacy mode is decided entirely at quote time. You can't set it at `/v3/swap`, which inherits the mode from the quote it executes. The flag isn't echoed in the response, so track it against `routeId` on your side.

Tracking is unaffected: `/track` resolves these swaps normally, including by `depositAddress`, because it reads the provider's status API rather than the public explorer.

#### Refunding to a different address

**Send it at quote time, not only at swap time.** Routes that can't honour it are filtered out of the quote, so the user only picks from ones that will work. `/v3/swap` takes it too and **overrides** the quote's value; omit it there and the quote's stands, then `sourceAddress`.

**Not every route can carry one.** It's forwarded to Chainflip, THORChain, Maya (streaming variants included), NEAR, Harbor and Flashnet. Garden and Mayan always refund the on-chain sender, so they're the ones dropped.

Where the refund rides in the swap memo, the sell chain's budget can also cut it — a Bitcoin OP\_RETURN is 80 bytes. `refundAddressSetting` decides what happens then:

| Value     | What happens to a route that can't honour it                                                                                                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `WARNING` | The route is returned with `refundAddressNotApplied` in `warnings`. The default.                                                            |
| `STRICT`  | The route is dropped at quote time, and `/v3/swap` rejects it with `refundAddressUnsupportedByRoute` or `refundAddressTooLongForSellChain`. |

**Under `WARNING`, check `warnings` before showing the user a refund address** — otherwise you promise one the swap won't use.

On Chainflip, a Bitcoin vault swap has no room for the address, so the route falls back to a deposit channel and raises `vaultSwapUnavailable` — deposit channels expire, vault swaps don't.

#### Example request

A simple request to trade `ETH.ETH` to `BTC.BTC` may omit the `providers` array if you can manage them in the response, but should include the amount and slippage settings.

A quote expires after 5 minutes. Once it does, you can request a new one, or one will be requested automatically if a swap is initiated using this `routeId` .

{% hint style="info" %}
Using the header `x-api-key` in your `/quote` request automatically applies your affiliate addresses and fee values set up through our [partners dashboard](/monetization.md#step-3-set-affiliate-fee-tiers) in the response parameters.
{% endhint %}

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST "https://api.swapkit.dev/v3/quote" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_VARIABLE_HERE" \
  -d '{
    "sellAsset": "ETH.USDC-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    "buyAsset": "BTC.BTC",
    "sellAmount": "300",
    "slippage": 2
  }'
```

{% endtab %}
{% endtabs %}

***

### Quote Response Schema

| Field            | Type                          | Description                                                                                                                                                                                                                                                          |
| ---------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `quoteId`        | `string`                      | UUID for this quote response                                                                                                                                                                                                                                         |
| `createdAt`      | `string`                      | ISO 8601 timestamp of when this quote response was created. Top level — a sibling of quoteId, not a per-route field.                                                                                                                                                 |
| `routes`         | `QuoteRoute[]`                | An array of routes with an individual `routeId` to request a swap with. `QuoteRoute` schema is explained below                                                                                                                                                       |
| `providerErrors` | `QuoteError[]` or `undefined` | Optional. Providers that were asked for a quote and declined. Present on a `200` response — it does not mean the request failed. Schema below; the codes are listed in [Route availability and providers errors](/spotlights/route-availability-and-size-limits.md). |
| `error`          | `string` or `undefined`       | In case of a bad request, root level `error` is provided.                                                                                                                                                                                                            |

#### Quote Route Schema

Each route identifies a provider or a group of providers for the swap. Each item in the routes array contains the information needed to compare between them:

<table><thead><tr><th width="265">Field</th><th width="96.1953125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>routeId</code></td><td><code>string</code></td><td>UUID of this specific swap response.</td></tr><tr><td><code>providers</code></td><td><code>array</code></td><td>List of providers available for this route (<code>CHAINFLIP</code>, <code>THORHCAIN</code> etc.).</td></tr><tr><td><code>sellAsset</code></td><td><code>string</code></td><td>The asset being sold (e.g., <code>“ETH.ETH”</code>).</td></tr><tr><td><code>buyAsset</code></td><td><code>string</code></td><td>The asset being bought (e.g., <code>“BTC.BTC”</code>).</td></tr><tr><td><code>sellAmount</code></td><td><code>string</code></td><td>Amount of the sell asset in smallest units.</td></tr><tr><td><code>expectedBuyAmount</code></td><td><code>string</code></td><td>Estimated amount of the buy asset to be received.</td></tr><tr><td><code>expectedBuyAmountMaxSlippage</code></td><td><code>string</code></td><td>Worst-case buy amount considering max slippage.</td></tr><tr><td><code>fees</code></td><td><code>array</code></td><td>List of fees applied to the swap (inbound, network, affiliate, service, outbound, liquidity).</td></tr><tr><td><code>estimatedTime</code></td><td><code>object</code></td><td>Estimated time for different phases of the swap.</td></tr><tr><td><code>totalSlippageBps</code></td><td><code>number</code></td><td>Expected total slippage.</td></tr><tr><td><code>legs</code></td><td><code>array</code></td><td>The different steps invovled in the swap.</td></tr><tr><td><code>warnings</code></td><td><code>array</code></td><td>Potential warnings about this swap provider.</td></tr><tr><td><code>txHint</code></td><td><code>string</code><br>(enum, optional)</td><td>How the deposit must be sent for this route — one of <code>simpleTransfer</code> (plain value transfer), <code>transferWithMemo</code> (transfer that must include the memo), or <code>contractCall</code> (submit as a smart-contract / EVM transaction). Returned at quote time so you can filter routes against your wallet's signing capabilities before calling <code>/v3/swap</code>, and guaranteed to match what <code>/v3/swap</code> builds for the same <code>routeId</code>. Absent on route patterns SwapKit hasn't classified — treat missing as unknown.</td></tr><tr><td><code>meta</code></td><td><code>object</code></td><td>Other information about the transaction and the assets involved.</td></tr><tr><td><code>meta.tags</code></td><td><code>array</code></td><td><code>"FASTEST"</code>, <code>"RECOMMENDED"</code> or <code>"CHEAPEST"</code> tag help sort the available routes.</td></tr><tr><td><code>nextActions</code></td><td><code>object</code></td><td>Data needed for the next request in the flow. <code>{ method: string; url: string; payload: object }</code></td></tr></tbody></table>

***

### Quote Error Schema

| Field       | Type                    | Description                                                                                                                                                  |
| ----------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `provider`  | `string`                | Specific ProviderName value                                                                                                                                  |
| `errorCode` | `string`                | One of the possible error codes listed below.                                                                                                                |
| `message`   | `string`                | Message relating to thrown error.                                                                                                                            |
| `minAmount` | `string` or `undefined` | The provider's minimum sell amount in human units, when the provider reported one. Present on most `sellAssetAmountTooSmall` entries — retry at or above it. |

#### Quote Error Codes and messages

<table><thead><tr><th width="154.80859375">Error</th><th>Message</th><th width="91.53125">Status Code</th><th>Scenario</th></tr></thead><tbody><tr><td><code>noRoutesFound</code></td><td>No routes found for swap from {sellAsset} to {buyAsset}</td><td>404</td><td>No valid swap path exists between the requested token pair.</td></tr><tr><td><code>blackListAsset</code></td><td>Asset {asset} is blacklisted</td><td>400</td><td>The sell or buy asset is identified as a scam token in our blacklist.</td></tr><tr><td><code>apiKeyInvalid</code> or <code>unauthorized</code></td><td>"Invalid API key" / "Unauthorized”</td><td>401</td><td>Missing, expired, or invalid API key in x-api-key header.</td></tr><tr><td><code>invalidRequest</code></td><td>"Request body is required and must be a valid JSON object”.</td><td>400</td><td>Request body is missing, null, or malformed JSON.</td></tr><tr><td><code>solanaOutputBelowRentExemptMinimum</code></td><td>Guaranteed output of {minimumOutput} lamports is below the {minimum} lamport rent-exempt minimum needed to fund destination {address}. Increase the swap amount or send to an existing account.</td><td>400</td><td>Same-chain Jupiter swap buying native SOL for a <code>destinationAddress</code> other than the sender, where the post-slippage minimum output is under Solana's 890,880-lamport (0.00089088 SOL) rent-exempt floor. No on-chain existence check, so an already-funded destination is rejected too. Raise the sell amount, or deliver to <code>sourceAddress</code>.</td></tr><tr><td><code>solanaTokenProgramUnavailable</code></td><td>Could not resolve the Solana token program for mint {tokenAddress}. Please retry.</td><td>502</td><td>Transient. SwapKit could not determine whether an SPL mint is Token or Token-2022 while preparing a same-chain Solana destination. Safe to retry.</td></tr></tbody></table>

The `invalidRequest` error may include additional details depending on the missing parameters. Make sure to check the JSON formatting in the request.

***

### Fees breakdown

Fees are categorized into different types based on their role in the swap process.

<table><thead><tr><th width="297">Fee Type</th><th>Description</th></tr></thead><tbody><tr><td><strong>Inbound</strong></td><td>Cost of getting the sell asset to the provider: estimated gas for the deposit, plus any provider ingress fee. Two entries when they're in different assets.</td></tr><tr><td><strong>Network</strong></td><td>Blockchain transaction fee for processing the swap.</td></tr><tr><td><strong>Affiliate</strong></td><td>Fee paid to the specified affiliate.</td></tr><tr><td><strong>Service</strong></td><td>SwapKit's service fee.</td></tr><tr><td><strong>Outbound</strong></td><td>Fee for transferring the buy asset to the destination address.</td></tr><tr><td><strong>Liquidity</strong></td><td>Fee applied by the liquidity provider to facilitate the swap.</td></tr></tbody></table>

Fees other than `inbound` are already reflected in `expectedBuyAmount`, whether taken from the input or the output — don't subtract them again. `inbound` is the only fee your wallet funds on top of `sellAmount`, and it isn't reflected in `expectedBuyAmount`.

**Chainflip is the exception.** Its `inbound` combines your gas with Chainflip's ingress fee, and only the gas is paid on top of `sellAmount` — the ingress is already reflected in `expectedBuyAmount`. Token deposits return the two separately (ingress in the deposited asset, gas in the chain's gas asset); native deposits sum them into one entry, so budget the full amount as an upper bound.

***

### Estimated time

The estimated time in seconds for the swap is divided into the following phases:

* **Inbound:** Time taken to receive the sell asset.
* **Swap:** Time taken for the swap process.
* **Outbound:** Time taken to transfer the bought asset to the destination. This includes the provider outbound time, not only the transaction time.
* **Total:** The sum of all time estimates.

#### **Example estimated time:**

```json
"estimatedTime": {
    "inbound": 30,
    "swap": 6,
    "outbound": 624,
    "total": 660
}
```

***

### Route metadata

The `meta` section provides additional information about the swap.

| **assets**          | Details of the involved assets, including price and image links.                            |
| ------------------- | ------------------------------------------------------------------------------------------- |
| **tags**            | \["FASTEST", "RECOMMENDED", "CHEAPEST"]                                                     |
| **approvalAddress** | Token-approval spender address. Present only for EVM ERC-20 sells that require an approval. |

`/v3/swap` returns a larger `meta` than this. Fields that only exist once a transaction is built — `allowance`, and the [deposit-channel fields](/swapkit-api/v3-swap-obtain-swap-transaction-details.md#deposit-channel-fields-in-meta) `providerDepositChannelId` / `depositChannelExpiration` — are documented on that page. `/v3/quote` never opens a deposit channel, so they never appear here.

#### **Example `meta` Object:**

```json
"meta": {
    "assets": [{
        "asset": "ETH.ETH",
        "price": 2752.14,
        "image": "https://tokens.swapkit.dev/images/eth.eth.png"
    }, {
        "asset": "BTC.BTC",
        "price": 97648,
        "image": "https://tokens.swapkit.dev/images/btc.btc.png"
    }],
    "tags": ["FASTEST"],
    "approvalAddress": "0x1111111254eeb25477b68fb85ed929f73a960582"
}
```

The `"tags"` help identify what SwapKit considers the best routes by filtering through the `["FASTEST", "RECOMMENDED", "CHEAPEST"]` labels.

<table><thead><tr><th width="283">Tag</th><th>Description</th></tr></thead><tbody><tr><td><strong>RECOMMENDED</strong></td><td>Best overall route based on output and speed.</td></tr><tr><td><strong>CHEAPEST</strong></td><td>The route with the maximum output.</td></tr><tr><td><strong>FASTEST</strong></td><td>The route with the shortest total estimated time.</td></tr></tbody></table>

To determine the `RECOMMENDED` route when multiple options are available, each route gets two normalized scores:

* **Output score (0-100)**: Compare the route's output to the maximum output of the available routes, multiplied by 100 for weight.\
  `(routeOutput / maxOutput) * 100`
* **Time score (0-50)**: Compare the route's expected confirmation time to the minimum confirmation time of the available routes, subtracting from 50 to give it a dynamic weight. The fastest route will obtain 50 points here.\
  `50 - abs(routeTime - minTime) / (maxTime - minTime)`

Output and time are weighted dynamically, depending on the difference between the fastest route and the one being analyzed.

<table><thead><tr><th width="283">Time spread (Current vs Fastest)</th><th>Output weight</th><th>Time weight</th></tr></thead><tbody><tr><td>≤ 60 seconds</td><td>100 %</td><td>0 %</td></tr><tr><td><strong>60s - 5 min</strong></td><td>95 %</td><td>5 %</td></tr><tr><td><strong>5 - 15 min</strong></td><td>90 %</td><td>10 %</td></tr><tr><td><strong>> 15 min</strong></td><td>80 %</td><td>20 %</td></tr></tbody></table>

The weights are then multiplied to the score, and the route with the highest total is tagged as `RECOMMENDED` . It is simply `outputScore * outputWeight + timeScore * timeWeight` .

***

### Next Actions

The `nextActions` object includes information about the request to make next. Generally it will point to the `/swap` endpoint which will return a transaction object, but for ERC-20 tokens the `/swap` endpoint may first return an `approvalTx` for spending approval, requiring a second `/swap` call to get the transaction.

For example, it could look like the following, which includes the `method`, `url` and `payload` to use. The `"soureAddress"` and `"destinationAddress"` need to be filled in:

```json
"nextActions": [
    {
        "method": "POST",
        "url": "/swap",
        "payload": {
            "routeId": "14ddcf49-4adb-4817-a55e-1bfb1296283d"
        }
    }
]
```
