> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raze.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Quote and swap

> Quote, build, sign, send. ExactIn and ExactOut, slippage, split routes, SOL wrapping.

Every swap is two calls: a quote, then a build for that quote. You sign and send what the build returns.

<Steps>
  <Step title="Quote">
    `GET /quote?inputMint=…&outputMint=…&amount=…&slippageBps=50` answers the route, the amounts and `otherAmountThreshold`. Every quote is checked to be buildable before it is served.
  </Step>

  <Step title="Build">
    `POST /swap-instructions` with `userPublicKey` and the quote (`quoteResponse`) answers the instructions; add `"serialize": true` for an unsigned transaction.
  </Step>

  <Step title="Sign and send">
    Sign the v1 transaction with the user's key and send it before its blockhash expires (about a minute).
  </Step>
</Steps>

```bash theme={null}
ROUTER=https://router.raze.bot   # or your own router, e.g. http://127.0.0.1:4700
SOL=So11111111111111111111111111111111111111112
USDC=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

# 0.1 SOL → USDC, 0.5% slippage
curl -s "$ROUTER/quote?inputMint=$SOL&outputMint=$USDC&amount=100000000&slippageBps=50" > quote.json

# Build it as an unsigned transaction for the user
jq -n --slurpfile q quote.json --arg u "$USER_WALLET" \
  '{userPublicKey: $u, quoteResponse: $q[0], serialize: true, prioritizationFeeLamports: "auto"}' |
  curl -s -X POST "$ROUTER/swap-instructions" -H 'content-type: application/json' -d @- > build.json

jq -r .swapTransaction build.json   # base64, unsigned v1: sign it and send it
```

## Three ways to name the route at build time

The build takes the route in one of three forms, in this order of precedence:

| Form | Body | What happens |
| - | - | - |
| The quote | `quoteResponse`: the whole quote object | The route is built as quoted. No re-quote and no age check: build right after quoting. |
| A ticket | `routeTicket` from the quote | Same, from a short signed string. Only when the router has a ticket secret configured; tickets expire (60 s by default). |
| A pair | `inputMint`, `outputMint`, `amount` and the quote parameters | Quoted and built in one call. |

With a quote or a ticket, any `inputMint`, `outputMint` (and with a ticket, `amount`) you also send must match it, or the build answers `400 quote_mismatch` / `route_ticket_mismatch`. If a pinned route crosses a venue the router has since stopped serving, the build answers `409 venue_red`: quote again.

<Note>
  `routeTicket` is not authentication. It is the quote, readable by anyone, with an HMAC so it cannot be altered. A router without `ROUTER_TICKET_SECRET` puts no ticket on its quotes and answers `400 invalid_route_ticket` to one.
</Note>

## ExactIn and ExactOut

`swapMode` is `ExactIn` (default) or `ExactOut`.

| | `amount` is | `otherAmountThreshold` is |
| - | - | - |
| `ExactIn` | What the user spends | The minimum output: `outAmount × (1 − slippage)` |
| `ExactOut` | What must arrive | The maximum input: `inAmount × (1 + slippage)` |

How an ExactOut is executed depends on the route:

* **One hop on a venue with an exact-output instruction** (`onchainExactOut` in [`/venues`](/api-reference/router/venues)): the output is pinned and the input is at most `otherAmountThreshold`.
* **Anything else** (several hops, or a venue without that instruction): the route is built as an exact-in that spends the slippage cap (`otherAmountThreshold`) with a minimum output equal to the requested amount. The user pays the cap, not `inAmount`, and any output above the requested amount stays with the user.

The build tells you which with `shape` (`exact_out` or `token_exact_in`) and gives the bounds as `minReturn` and `maxAmountIn`.

## Slippage

* `slippageBps` defaults to **50** (0.5%) and cannot exceed 10000.
* A `slippageBps` in the build body **replaces** the quote's (or the ticket's). Send it only on purpose.
* Your deploy's admin can cap slippage per venue on chain. A lower cap makes a route revert beyond it, even inside the slippage you asked for.

## Choosing venues

| Parameter | Effect |
| - | - |
| `dexes` (alias `includeDex`) | Only these venues. Unknown names are ignored if at least one is known; if none is, `400`. |
| `excludeDexes` (alias `excludeDex`) | Never these venues. Unknown names are ignored. |
| `maxHops` | At most this many hops per route (1–4, default the router's ceiling of 4) |
| `onlyDirectRoutes` | One hop only |
| `reserveKeys` | Account keys you will add to the transaction yourself: only routes that still fit 64 keys are served |
| `forJitoBundle` | Leave room for a Jito tip |

Lists are comma-separated in the query string, or JSON arrays in a `POST /quote` body. Venues the router's price checks currently hold out are removed from every quote automatically; [`GET /ready`](/api-reference/router/ready) lists them in `red_pass`.

## Split routes

`allowSplit=true` lets the router split an ExactIn across two routes in one transaction, when the split beats the best single route by at least 1 bps and still fits the transaction. In the quote, `routePlan` lists route A's steps then route B's; the first step of each carries its share in `percent` (rounded) and `bps` (exact).

<Warning>
  A split build has **two** swap instructions, in `swapInstructions`; `swapInstruction` is only the first. A client that assembles the transaction from `swapInstruction` alone swaps a fraction of the input. Ask for splits only if you use `swapInstructions` or `serialize: true`.
</Warning>

Splits are not served for ExactOut or with a platform fee.

## Wrapping SOL

`wrapAndUnwrapSol` (alias `unwrapSol`) defaults to **true**:

* SOL in: the build moves the lamports into the user's wrapped-SOL account (creating it) and closes it after the swap.
* SOL out: the build unwraps by closing the user's wrapped-SOL account, except when the output goes to another wallet (`destinationTokenAccount`), which receives wrapped SOL.

With `false`, the swap spends from and pays into the user's wrapped-SOL token account and nothing is wrapped or closed.

## Sending the output elsewhere

`destinationTokenAccount` (alias `recipient`) is the **wallet** that receives the output, not a token account: the output lands in that wallet's associated token account, created if missing. A token account there is refused with `400 bad_recipient` (it would have received into a nested account the owner cannot see).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.