> 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/api-reference/v3-swap-obtain-swap-transaction-details.md).

# /v3/swap - Obtain swap transaction details

Use an existing routeId to obtain a swap's transaction details.

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

After the user has accepted a quote, perform a request to the `/swap` endpoint to obtain transaction details. Use a quote's `routeId` to identify it (it is cached for 5 minutes), providing additional details about the involved addresses.

### Request Schema

<table><thead><tr><th width="244">Parameter</th><th width="92">Type</th><th width="96">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>routeId</code></td><td><code>string</code></td><td>Yes</td><td>The ID of the route to swap. Obtained from a previous <code>/v3/quote</code> response</td></tr><tr><td><code>sourceAddress</code></td><td><code>string</code></td><td>Yes</td><td>Blockchain address to send the asset from. Must be a valid address for the sell asset's chain<br><br>On a UTXO sell chain this may name several addresses separated by <code>;</code>. This endpoint builds the transaction, so send the <strong>same list</strong> you sent to <code>/v3/quote</code> — send just one address here and the transaction is funded from that address alone. See <a href="/api-reference/v3-quote-request-a-swap-quote.md#funding-a-swap-from-several-addresses">Funding a swap from several addresses</a>.<br><br>Refunds go here unless you pass <code>refundAddress</code>. Must be an address the user controls and can receive at, <a href="/guides/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>Yes</td><td>Recipient blockchain address to send the asset to. Must be a valid address for the buy asset's chain</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. Overrides the value sent to <code>/v3/quote</code>, then falls back to it, then to <code>sourceAddress</code>. See <a href="/api-reference/v3-quote-request-a-swap-quote.md#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 when the route can't honour the address. See <a href="/api-reference/v3-quote-request-a-swap-quote.md#refunding-to-a-different-address">Refunding to a different address</a>. Ignored when no refund address applies.</td></tr><tr><td><code>disableBuildTx</code></td><td><code>boolean</code></td><td>No</td><td>Whether to skip providing a built transaction, ready to sign by the wallet.</td></tr><tr><td><code>disableBalanceCheck</code></td><td><code>boolean</code></td><td>No</td><td>Whether to skip balance validation. If <code>false</code> or omitted, checks that source address has sufficient balance. Do not use without consulting SwapKit devs first. Default: <code>false</code></td></tr><tr><td><code>disableEstimate</code></td><td><code>boolean</code></td><td>No</td><td>Whether to skip on-chain gas estimation when building the transaction. Default: <code>false</code></td></tr><tr><td><code>allowSmartContractSender</code></td><td><code>boolean</code></td><td>No</td><td>Whether to allow the source address to be a smart contract, <a href="/guides/smart-contract-limitations-and-edge-cases.md#solana-multisig-vaults-and-pdas-off-curve-addresses">or an off-curve Solana address</a>. Do not use without consulting SwapKit devs first. Default: <code>false</code></td></tr><tr><td><code>allowSmartContractReceiver</code></td><td><code>boolean</code></td><td>No</td><td>Whether to allow the destination address to be a smart contract, <a href="/guides/smart-contract-limitations-and-edge-cases.md#solana-multisig-vaults-and-pdas-off-curve-addresses">or an off-curve Solana address</a>. Do not use without consulting SwapKit devs first. Default: <code>false</code></td></tr><tr><td><code>disableSecurityChecks</code></td><td><code>boolean</code></td><td>No</td><td>Whether to bypass address format validation and security checks. Default: <code>false</code></td></tr><tr><td><code>overrideSlippage</code></td><td><code>boolean</code></td><td>No</td><td><strong>Deprecated — use <code>slippageSetting</code></strong>, which supersedes it. Default: <code>false</code></td></tr><tr><td><code>slippageSetting</code></td><td><code>string</code></td><td>No</td><td>How <code>/v3/swap</code> reacts when the re-priced route no longer meets the minimum it published. <code>WARNING</code>, <code>STRICT</code> or <code>OVERRIDE</code> — <a href="#slippage-settings">see Slippage settings</a>. Default: <code>WARNING</code>.</td></tr><tr><td><code>enableSweep</code></td><td><code>boolean</code></td><td>No</td><td>Whether to enable max-spend sweep behaviour for UTXO assets (BTC, LTC, DOGE, BCH). Set to <code>true</code> to send the full spendable balance instead of exactly <code>sellAmount</code> when the swap would otherwise leave unspendable dust. Opt-in; if omitted, inherits <code>enableSweep</code> from the <code>/v3/quote</code> call that created the <code>routeId</code>. Default: <code>false</code>.</td></tr><tr><td><code>gasCheck</code></td><td><code>boolean</code></td><td>No</td><td>Opt-in native-gas balance check for <strong>token sells</strong> (gas-asset sells are covered by <code>insufficientBalance</code> instead). When the wallet can't cover the network fee, the route carries an <code>insufficientGas</code> warning and the transaction is still returned. Inherits from <code>/v3/quote</code> when omitted. Default: <code>false</code>.</td></tr></tbody></table>

{% hint style="warning" %}
When you test your integration, use an address with enough `sellAsset` balance to cover the swap. This will ensure you receive complete responses with a valid transaction object.
{% endhint %}

For example, the request could be as simple as this (this `routeId` will not work for you, as it has now expired):

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

```sh
curl -X 'POST' \
  'https://api.swapkit.dev/v3/swap' \
  -H 'Content-Type: application/json' \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "routeId": "85bb4fa2-3a65-4d22-b20b-e43d028d83e6",
    "sourceAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "destinationAddress": "357a3So9CbsNfBBgFYACGvxxS6tMaDoa1P"
}'
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
A fresh quote is fetched on every `/swap` call to refresh price and slippage. Route IDs are cached for 5 minutes\
If the `routeId` is older than 5 minutes, it will not be cached anymore and won't be recognized by the swap endpoint.
{% endhint %}

#### Disabling transaction building

* `disableBuildTx` is the most effective filter. Data on where to send the tokens to swap will be provided, but the transaction building won't be performed. This avoids all balance checks and errors derived from it.
* `disableBalanceChecks` still tries to build a transaction without checking the balance of the address. This works on some chains, like EVM, but will fail on UTXO chains because building a transaction requires checking the balance (the flag is not applied).

Using them together ensures no errors from wallet balance or other transaction building errors are returned. This is only recommended for advanced integrations, where you are sure you can build the transaction yourselves.

#### Slippage settings

Every `/v3/swap` call re-prices the route, then checks the refreshed output against two independent guards. `slippageSetting` governs how each one reacts:

<table data-header-hidden><thead><tr><th></th><th></th><th></th><th width="215.078125"></th><th></th></tr></thead><tbody><tr><td>Guard</td><td>Compares</td><td><code>WARNING</code> (default)</td><td><code>STRICT</code></td><td><code>OVERRIDE</code></td></tr><tr><td><strong>Published floor</strong></td><td>Refreshed output vs the route's <code>expectedBuyAmountMaxSlippage</code> — the worst case <code>/v3/quote</code> already showed you</td><td><code>outputBelowPublishedFloor</code> in <code>warnings[]</code>, transaction still returned</td><td><code>409 outputBelowPublishedFloor</code></td><td>skipped</td></tr><tr><td><strong>Deviation guard</strong></td><td>Refreshed output vs the original quote, at more than 5% <strong>and</strong> more than $10</td><td><code>400 outputAmountDeviationTooHigh</code></td><td><code>400 outputAmountDeviationTooHigh</code></td><td>skipped</td></tr></tbody></table>

Two things the table can't show. The deviation guard runs **first**, so `WARNING` can't let a deviation breach through by also breaching the floor. And the floor check is skipped entirely on sweeps, which re-solve the sell amount — a smaller output there is correct rather than a breach.

{% hint style="info" %}
`overrideSlippage: true` still works and still means `OVERRIDE`, but it's deprecated. When both are sent, `slippageSetting` wins.
{% endhint %}

### Swap Response Schema

<table><thead><tr><th width="271">Field</th><th width="85">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>swapId</code></td><td><code>string</code></td><td>UUID of this specific swap response.</td></tr><tr><td><code>createdAt</code></td><td><code>string</code></td><td>ISO 8601 timestamp of when this swap response was built.</td></tr><tr><td><code>quoteCreatedAt</code></td><td><code>string</code></td><td>ISO 8601 timestamp of the underlying quote. Note the unit change from <code>expiration</code>, which is unix seconds as a string.</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>tx</code></td><td>varies</td><td>Explained below</td></tr><tr><td><code>approvalTx</code></td><td><code>object</code><br>(optional)</td><td>For EVM sell chain. When a token approval transaction is required to be submitted before the <code>tx</code> can be broadcasted. See <a href="#the-approvaltx-object">below</a> for more details.</td></tr><tr><td><code>targetAddress</code></td><td><code>string</code><br>(optional)</td><td>The address the swap transaction targets — a DEX aggregator/router contract for EVM swaps, or the inbound vault address for non-EVM cross-chain swaps. Optional: it is omitted for deposit-channel routes (e.g. Chainflip), where the send destination comes from the deposit address in <code>meta</code> or is resolved during <code>tx</code> building instead.</td></tr><tr><td><code>memo</code></td><td><code>string</code></td><td>Optional. Memo with instructions for swap.</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).</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 involved steps in the swap.</td></tr><tr><td><code>warnings</code></td><td><code>array</code></td><td>Potential warnings about this swap provider. Warnings never block the response — <code>tx</code> is still returned.</td></tr><tr><td><code>meta</code></td><td><code>object</code></td><td>Other information about the transaction. A superset of the <code>/v3/quote</code> route metadata — it adds the swap-only <a href="#the-meta.allowance-field"><code>allowance</code></a> and, on routes that open a deposit channel, <a href="#deposit-channel-fields-in-meta">the deposit-channel fields</a>.</td></tr><tr><td><code>routeId</code></td><td><code>string</code></td><td>UUID of the specific route this swap was built from — the same <code>routeId</code> returned by <code>/v3/quote</code> and passed back in the <code>/v3/swap</code> request.</td></tr><tr><td><code>sourceAddress</code></td><td><code>string</code></td><td>Blockchain address to send the asset from.</td></tr><tr><td><code>destinationAddress</code></td><td><code>string</code></td><td>Recipient blockchain address to send the asset to.</td></tr><tr><td><code>txHint</code></td><td><code>string</code><br>(enum, optional)</td><td>How the deposit must be sent — one of <code>simpleTransfer</code> (plain value transfer), <code>transferWithMemo</code> (transfer that must include the <code>memo</code>), or <code>contractCall</code> (submit as a smart-contract / EVM transaction). Also returned by /v3/quote — the value is identical for the same <code>routeId</code>. Present even when no <code>tx</code> is built.</td></tr><tr><td><code>txType</code></td><td><code>string</code><br>(enum, optional)</td><td>The format of the returned <code>tx</code>. <a href="/api-reference/transaction-formats-by-txtype.md">See Transaction Formats by txType</a>. Also mirrored at <code>meta.txType</code>.</td></tr><tr><td><code>inboundAddress</code></td><td><code>string</code><br>(optional)</td><td>For deposit/memo-based providers, the protocol's inbound vault address that funds are sent to. Present only when the route settles via an inbound deposit rather than a direct contract call.</td></tr><tr><td><code>shieldedMemo</code></td><td><code>object</code><br>(optional)</td><td>Shielded-Zcash source only. <code>{ unifiedAddress: string, uivk?: string }</code>. Send a 0-value shielded note carrying the <code>memo</code> to <code>unifiedAddress</code> in the <strong>same transaction</strong> as the value output to <code>inboundAddress</code>. <code>uivk</code> is MAYAChain's unified incoming viewing key for decrypting the note. See <a href="/guides/chain-specific-guides/zcash-shielded-and-unified-addresses.md">Zcash shielded &#x26; unified addresses</a> for more details.</td></tr><tr><td><code>expiration</code></td><td><code>string</code><br>(optional)</td><td><strong>Quote deadline only — not the deposit window.</strong> Unix <strong>seconds</strong>, as a string (not ISO 8601). For most providers this is a flat <code>quoteCreatedAt + 3600s</code> rather than a provider-supplied value; only FLASHNET and MAYAN return their own deadline, and CHAINFLIP returns none at all. If you need to know how long a deposit channel accepts funds, use <code>meta.depositChannelExpiration</code> — <a href="#deposit-channel-fields-in-meta">see below</a>.</td></tr></tbody></table>

#### The `approvalTx` object

<table><thead><tr><th width="227.8984375">Field</th><th width="128.6484375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>approvalTx.to</code></td><td><code>string</code></td><td>Token contract address to send the approval</td></tr><tr><td><code>approvalTx.from</code></td><td><code>string</code></td><td>User wallet address.</td></tr><tr><td><code>approvalTx.value</code></td><td><code>string</code></td><td>ETH value — always <code>"0"</code> for approvals.</td></tr><tr><td><code>approvalTx.data</code></td><td><code>string</code></td><td>Encoded <code>approve()</code> call data.</td></tr><tr><td><code>approvalTx.gasLimit</code></td><td><code>string</code></td><td>Estimated max gas units for the approval transaction, as a hex quantity string</td></tr><tr><td><code>approvalTx.gasPrice</code></td><td><code>string</code></td><td>Gas price in wei per gas unit, as a hex quantity string. Legacy (type-0) gas pricing.</td></tr></tbody></table>

#### The `meta.allowance` field

| Field            | Type                | Description                                                                                                                                                                                                                      |
| ---------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `meta.allowance` | `string` (optional) | The sell token's current on-chain allowance for the spender this route pulls through, in **base units**. Usually that is `meta.approvalAddress` — see [How the allowance is read](#how-the-allowance-is-read) for the exception. |

* **`"0"` is a normal value** — it means no allowance has been granted yet, not that the field is missing.
* **It is not the approval signal.** It's returned whether or not an approval is needed; the presence of `approvalTx` remains the only "approval required" indicator. Don't derive one from the other — the two are gated separately, so `allowance` can be absent on a route that still returns an `approvalTx`.
* **Omitted** when an ERC-20 allowance isn't a meaningful concept for the route: native gas-asset sells, non-EVM sell chains, and deposit-channel routes (e.g. Chainflip) that move funds with a plain `transfer` rather than a `transferFrom` pull.

#### How the allowance is read

The allowance is read live from the sell chain on every `/v3/swap` call — there is no cached value — and compared against **this route**. Two consequences worth designing around:

* **The comparison is amount- and spender-scoped.** `approvalTx` appears when the allowance is below `sellAmount` for the spender *this route* pulls through. A partial allowance therefore still produces an `approvalTx`, and an allowance granted to a different provider's spender does not count — so switching routes can reintroduce an approval step for a token the user has already approved once. The spender is usually `meta.approvalAddress`, but not always: routes that swap in through THORChain, Chainflip or NEAR are checked against the token-transfer proxy instead.
* **The read can trail the chain tip** by a block or two. After broadcasting an approval, wait on your own confirmation rather than re-calling `/v3/swap` until `approvalTx` disappears.

{% hint style="warning" %}
**A missing `approvalTx` is fail-open.** If the allowance read fails, the swap is still returned, with no `approvalTx` — the same shape as "no approval needed". The reasoning is that a genuinely missing allowance reverts the transaction anyway, but it does mean the absence of `approvalTx` is not proof that the allowance is in place. Verify it yourself if your flow depends on certainty.
{% endhint %}

#### Deposit-channel fields in `meta`

When a route settles by opening a deposit channel, `/v3/swap` returns the channel's id and its deadline. These are **`/v3/swap` only** — `/v3/quote` never opens a channel, so they never appear in a quote response.

<table><thead><tr><th width="290">Field</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>meta.providerDepositChannelId</code></td><td><code>string</code><br>(optional)</td><td>The provider's own id for the deposit channel, returned as soon as the channel is opened. Pass it to <a href="/api-reference/track-request-the-status-of-a-swap.md"><code>/track</code></a> as <code>depositChannelId</code> to follow the swap without a transaction hash.</td></tr><tr><td><code>meta.depositChannelExpiration</code></td><td><code>number</code><br>(optional)</td><td>Unix <strong>seconds</strong> after which the channel stops accepting a deposit. <strong>This is the deadline where user funds are at stake</strong> — drive your deposit countdown from this, never from <code>expiration</code>.</td></tr><tr><td><code>meta.depositChannelExpirationBlock</code></td><td><code>number</code><br>(optional)</td><td>Chainflip only. The raw source-chain block the channel expires at (<code>sourceChainExpiryBlock</code>). Informational — <code>depositChannelExpiration</code> is not derived from it.</td></tr></tbody></table>

{% hint style="warning" %}
`expiration` and `meta.depositChannelExpiration` are different deadlines with different units. `expiration` is the quote deadline — a string of unix seconds, usually just one hour out. `meta.depositChannelExpiration` is the channel deadline — a number. Using `expiration` for a deposit countdown will show a window \~23h shorter than the real one.
{% endhint %}

**Which providers return them**

<table><thead><tr><th width="270">Route</th><th width="150">Channel id</th><th width="200">Expiration</th><th>Expiration block</th></tr></thead><tbody><tr><td><code>CHAINFLIP</code> / <code>CHAINFLIP_STREAMING</code>, deposit-channel</td><td>yes</td><td>channel open + a flat 24h</td><td>yes</td></tr><tr><td><code>CHAINFLIP</code> vault swaps</td><td>—</td><td>—</td><td>—</td></tr><tr><td><code>NEAR</code></td><td>yes</td><td>provider's quote deadline</td><td>—</td></tr><tr><td><code>FLASHNET</code></td><td>yes</td><td>channel open + a flat 24h</td><td>—</td></tr><tr><td><code>GARDEN</code></td><td>yes</td><td>may be omitted</td><td>—</td></tr><tr><td>all other providers</td><td>—</td><td>—</td><td>—</td></tr></tbody></table>

Chainflip and Flashnet channels close after a flat 24 hours regardless of source chain, so that the network can rotate its vaults and authority sets. The deadline is computed from that fixed lifetime, not from source-chain block times.

On a multi-provider route these fields describe the channel you actually deposit into — the first leg's. When Chainflip is a later leg there is no channel for the user to deposit to, and the fields are absent.

#### The `tx` field

We provide the ready to be signed transaction in the `tx` field. It can be an object or a string, depending on the source chain of the swap.

* VM sell chain - Ethers V6 Transaction <https://docs.ethers.org/v6/api/transaction/#Transaction>
* UTXO sell chain (BTC, BCH, LTC, DOGE) - base64 encoded PSBT ZCash sell chain - By default a base64 encoded PSBT using <https://github.com/BitGo/BitGoJS/blob/master/modules/utxo-lib/src/bitgo/UtxoPsbt.ts#L161> library is returned.We also support returning of an unsigned PCZT using <https://github.com/zcash/librustzcash> - Please reach out for more information.
* TRON sell chain - A TransactionBuilder object from the TronWeb lib <https://tronweb.network/docu/docs/API%20List/transactionBuilder/sendAsset#example>
* Cosmos sell chains (including THOR & MAYA) - A native Cosmos transaction object <https://tutorials.cosmos.network/academy/2-cosmos-concepts/3-transactions.html#generating-transactions>

As an example, for an EVM sell chain it might look like this. In this case, it's a simple transfer without any contract involved:

```json
"tx": {
        "to": "0x4e6960159d85254cb8e88483793f6fa8e9a49a4c",
        "from": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "gas": "0x5208",
        "gasPrice": "0x9129260",
        "value": "3000000000000000000",
        "data": "0x"
    },
```

The transaction can also use [SLIP-0024 payload for verification](/guides/slip-0024-transaction-payload-signing.md). Reach out to use if you are interested.

***

### **Swap Errors**

<table><thead><tr><th width="179">Field</th><th width="154">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>provider</code></td><td><code>string</code></td><td>Specific provider name</td></tr><tr><td><code>errorCode</code></td><td><code>string</code></td><td>One of the possible error codes listed below.</td></tr><tr><td><code>message</code></td><td><code>string</code></td><td>Message related to the error.</td></tr></tbody></table>

#### **Error codes and messages**

<table><thead><tr><th>Error</th><th>Message</th><th width="111">Status Code</th><th>Scenario</th></tr></thead><tbody><tr><td><code>swapRouteNotFound</code></td><td>Route not found for routeId: {routeId}</td><td>404</td><td>The routeId doesn't exist in cache (expired after 5 minutes or never existed). Client must request a new quote first.</td></tr><tr><td><code>refundAddressUnsupportedByRoute</code></td><td>Provider {provider} always refunds the sender</td><td>400</td><td>Only under <code>refundAddressSetting: STRICT</code>, when the route's provider can't send a refund anywhere but the on-chain sender.</td></tr><tr><td><code>refundAddressTooLongForSellChain</code></td><td>Refund address does not fit the {provider} memo on {sellChain}</td><td>400</td><td>Only under <code>refundAddressSetting: STRICT</code>. The provider carries the refund address in the swap memo and this sell chain has no room for it. Carries <code>{ provider, sellChain }</code>.</td></tr><tr><td><code>isSanctionedAddress</code></td><td>Address {address} is sanctioned or risky</td><td>400</td><td>Source or destination address flagged by screening service (Chainalysis/Elliptic). Addresses are screened against sanctions lists and risk databases</td></tr><tr><td><code>apiKeyInvalid</code> / <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>insufficientBalance</code></td><td>Insufficient balance for {chain} amount {amount} at address {address}</td><td>400</td><td>When <code>disableBalanceCheck</code> is <code>false</code>, source address doesn't have enough tokens to complete the swap. Balance fetched from blockchain and compared to sellAmount.</td></tr><tr><td><code>insufficientGas</code></td><td>Cannot build transaction. Insufficient gas balance on chain {chain}</td><td>400</td><td>EVM token sell where the node reports insufficient funds while estimating gas. Distinct from the non-blocking <code>insufficientGas</code> warning in <code>warnings[]</code>, which does not fail the request.</td></tr><tr><td><code>invalidSourceAddress</code></td><td>Invalid source address: {address}</td><td>400</td><td>Source address validation fails (invalid format, smart contract when not allowed, or fails security checks). Also returned for an off-curve Solana source unless <code>allowSmartContractSender: true</code>.</td></tr><tr><td><code>invalidDestinationAddress</code></td><td>Invalid destination address: {address}</td><td>400</td><td>Destination address validation fails (invalid format, smart contract when not allowed, or fails security checks). Also returned for off-curve Solana destinations unless <code>allowSmartContractReceiver: true</code></td></tr><tr><td><code>outputAmountDeviationTooHigh</code></td><td>Output amount deviation too high. Original: {originalAmount}, Refreshed: {refreshedAmount}, Deviation: {percentageChange}%</td><td>400</td><td>Quote was refreshed and the new output amount deviates more than 5% from the cached quote. Protects users from price slippage. Bypassed only by <code>slippageSetting: "OVERRIDE"</code></td></tr><tr><td><code>noRoutesFound</code></td><td>No routes found for swap from {sellAsset} to {buyAsset}</td><td>404</td><td>When quote is refreshed, no valid routes are returned from providers. Rare - indicates liquidity dried up or all providers failed.</td></tr><tr><td><code>memoTooLongForSourceChain</code></td><td>Destination address is too long for the source chain's memo limit</td><td>400</td><td>Generated memo exceeds the source chain's memo capacity (e.g. a long unified refund address on a transparent source).</td></tr><tr><td><code>zcashMemoTooLong</code></td><td>Zcash memo exceeds the byte budget</td><td>400</td><td>Final Zcash memo exceeds its byte budget (80B transparent source / 512B shielded source).</td></tr><tr><td><code>zcashShieldedMemoUnavailable</code></td><td>Maya shielded memo support is unavailable</td><td>503</td><td>MAYAChain's shielded-memo config is disabled or absent when a shielded Zcash deposit is requested.</td></tr><tr><td><code>zcashShieldedRefundMissing</code></td><td>Refund address missing from memo for shielded Zcash deposit</td><td>500</td><td>Safety guard: shielded-source memo produced without the refund address embedded; swap aborted to prevent unrecoverable funds.</td></tr><tr><td><code>invalidAddressForChain</code></td><td>Invalid address for chain</td><td>400</td><td>The derived refund address fails Zcash validation.</td></tr><tr><td><code>outputBelowPublishedFloor</code></td><td>Refreshed output {refreshedAmount} is below the published floor {publishedFloor}</td><td>409</td><td>The re-priced route settles for less than the <code>expectedBuyAmountMaxSlippage</code> the original quote published. Only raised under <code>slippageSetting: "STRICT"</code> — <a href="#slippage-settings">see Slippage settings</a>.</td></tr><tr><td><code>litecoinMwebAddressUnsupported</code></td><td>Litecoin MWEB addresses are not supported (source|destination address {address})</td><td>400</td><td>An <code>ltcmweb1…</code> address was supplied as source or destination. Not waivable by <code>disableSecurityChecks</code>. <a href="/guides/smart-contract-limitations-and-edge-cases.md#litecoin-mweb-addresses">See Litecoin MWEB addresses</a>.</td></tr><tr><td><code>geoRestrictedToken</code></td><td>{asset} is not available in your region ({country})</td><td>451</td><td>A geo-restricted asset executed from a restricted jurisdiction. Re-checked here, so a route priced in a permitted region cannot be executed from a blocked one. <a href="/guides/tokenized-equities-and-geo-restrictions.md">See Tokenized equities &#x26; geo-restrictions</a>.</td></tr></tbody></table>

***

### Additional Notes

* **Quote price refresh:** The quote response is cached for 5 minutes. Each `/swap` call fetches a fresh quote from the blockchain to refresh price and slippage; after 5 minutes the `routeId` expires and `/swap` returns a `swapRouteNotFound` error. To get the swap payload, always call `/swap` with the `nextActions` from the quote response.
* **Balance check:** By default we check if the `sourceAddress` has a sufficient balance. Since OKW is already the wallet, you can use `disableBalanceCheck: true` in the body of the `/swap` request.
* **Latency:** The `/swap` endpoint is more costly and slower. It builds the transaction payload, including fetching UTXOs and building PSBT when required, performs a balance check, and automatically runs **address screening on every `/swap` call**. It also opens a deposit channel when NEAR or Chainflip providers are used, which can take up to 2.5s. Setting `gasCheck: true` adds a native-balance lookup, and on TRON an extra fee estimate for low-balance wallets.

  Calling this endpoint should only be done after the user has selected a quote as their swap route.
* The `/swap` response also carries over some of the same fields returned by `/quote`, such as `estimatedTime`, `totalSlippageBps`, and the `fees` breakdown.

Some of these can be skipped by using the optional parameters listed in the [request schema](#request-schema).

**Optional `/swap` params:**

1. `disableBalanceCheck` : skip checking the `sourceAddress` balance of the `fromAsset` . Recommended for wallets that do this check internally.
2. `disableEstimate` : skip gas estimation for EVM chains.
3. `overrideSlippage` : receive a `/swap` transaction payload even if the output amount doesn’t fit within the slippage parameter provided in the referenced `/quote` through the `routeId` (relevant if a new quote has to be fetched).
4. `gasCheck` : opt in to the native-gas balance check on token sells, adding an `insufficientGas` warning when the wallet can't cover the network fee. Off by default; costs an extra balance lookup.
