> For the complete documentation index, see [llms.txt](https://titan-exchange.gitbook.io/titan/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://titan-exchange.gitbook.io/titan/developer-doc/swap-api/reference/gateway/gateway-quote-swap.md).

# Quote Swap

**Returns swap quotes with executable instructions and address lookup tables — the Gateway equivalent of** [**NewSwapQuoteStream**](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md)**.** A single REST call instead of a WebSocket stream.

```
GET /api/v1/quote/swap
```

**Authentication** — `Authorization: Bearer <token>` header or `?auth=<token>` query param. See [Connection & Negotiation](/titan/developer-doc/swap-api/reference/direct/connection.md#authentication) for JWT details.

***

## Query parameters

### Required

* **`inputMint`** — Input token mint address (base58).
* **`outputMint`** — Output token mint address (base58).
* **`amount`** — Amount in the smallest unit (e.g. lamports for SOL). **Not scaled by decimals.**
* **`userPublicKey`** — Wallet public key (base58). Required for transaction/instruction generation.

### Swap options

* **`slippageBps`** — Maximum allowed slippage, in basis points. Server default applies if omitted.
* **`dexes`** — Comma-separated venue labels to **include**. See [GetVenues](/titan/developer-doc/swap-api/reference/gateway/gateway-info.md#venues) for valid labels.
* **`excludeDexes`** — Comma-separated venue labels to **exclude**.
* **`venueAllowlist`** — Comma-separated venue **addresses** (base58) to restrict routing to. Filters by individual pool address, unlike `dexes`/`excludeDexes` which filter by venue label.
* **`venueBanlist`** — Comma-separated venue **addresses** (base58) to exclude. Overrides `venueAllowlist` — an address in both lists is always excluded.
* **`noVoteAccounts`** — `"true"` to exclude a server-configured set of market-maker venues from routing. These venues are included as normal when omitted or `"false"`.
* **`providers`** — Comma-separated provider IDs. See [ListProviders](/titan/developer-doc/swap-api/reference/gateway/gateway-info.md#providers) for valid IDs.
* **`numQuotes`** — Maximum number of quotes to return. If more providers can quote, the worst are filtered out (by amount in/out depending on swap mode). Server default applies if omitted; validated against the server's configured bounds. On Titan Direct this is part of the streaming `update` object — on the Gateway it's a flat query param.
* **`onlyDirectRoutes`** — `"true"` to skip multi-hop routes. Only direct swaps between input and output mint.
* **`addSizeConstraint`** — `"true"` to only return quotes that fit within the transaction size limit.
* **`sizeConstraint`** — Custom max transaction size in bytes. Default is set by the server (normally slightly less than 1232).
* **`accountsLimitTotal`** — Max total accounts per route. Default: 64.
* **`accountsLimitWritable`** — Max writable accounts per route. Default: 64.
* **`transactionTemplate`** — A [`TransactionTemplate`](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md#transaction-template) encoded via **MessagePack then Base64**, passed as a query-string value. Reserves room in the transaction for instructions and ALTs you plan to prepend/append yourself, so Titan sizes routes to fit alongside them. **Incompatible with `accountsLimitTotal`, `accountsLimitWritable`, and `sizeConstraint`.**

### Transaction options

* **`feeAccount`** — Token account for collecting platform fees (base58). **Must already exist on-chain.**
* **`feeBps`** — Fee amount in basis points.
* **`feeFromInputMint`** — `"true"` to take fee from input mint. Default: `"false"` (fee taken from output mint).
* **`closeInputTokenAccount`** — `"true"` to close the input token account as part of the transaction.
* **`createOutputTokenAccount`** — `"true"` to add an idempotent ATA creation instruction.
* **`outputAccount`** — Custom output token account (base58). Defaults to the user's ATA.
* **`outputWsol`** — `"true"` to leave the output as **wrapped SOL** (the wSOL SPL token) instead of unwrapping it to native SOL. Default: `"false"` (output is unwrapped to native SOL). **Only has an effect when `outputMint` is wSOL** (`So11111111111111111111111111111111111111112`); ignored for any other output mint. Use it when the next step in your flow expects a wSOL token account rather than native lamports. **Requires `titanSwapVersion=3`.**
* **`payer`** (base58) — Separate funder that covers the SOL-denominated costs of the swap: network fees, rent for any ATA the router creates (wSOL wrap ATA, output ATA), and the destination for the rent refund when the wSOL ATA is closed. **The payer must sign the transaction alongside the user for it to land.** **Requires `titanSwapVersion=3`.**
* **`positiveSlippageFeeReceiver`** (base58) — Token account that receives any surplus when realized DEX output exceeds the quoted `outAmount`. **The skim is capped at 10 bps of `outAmount`** — any surplus beyond that stays with the user. **Must be a token account of the `outputMint`** — a wallet pubkey or wrong-mint token account fails the transaction at execution. If you want the surplus to land in a specific wallet, pass that wallet's ATA under `outputMint` (and make sure it exists before the tx runs — the router does not auto-create this account). **Requires `titanSwapVersion=3`.**

### V3 router

* **`titanSwapVersion`** — `"3"` to opt into the V3 router. Titan returns V2 by default and will switch to V3 in a future release. See [NewSwapQuoteStream → Swap V3](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md#swap-v3) for details.

### Performance options

* **`simulate`** — `"true"` (default) or `"false"`. Simulated quotes give **more reliable execution and tighter realized slippage** because the server has verified the route against current on-chain state before returning it. **Set to `"false"` to skip simulations** — significantly reduces latency by removing an RPC round-trip, at the cost of that pre-flight check.
* **`maxPriceDeviationBps`** — Max allowed deviation from reference price, in basis points. Default: `1000` (10%). **Set to `10000` or higher to disable price checking entirely.**

### Response options

* **`includeAltContents`** — `"true"` to include full Address Lookup Table accounts in the response's `alts` field. Defaults to `"false"`; when omitted or `"false"`, each route returns only the ALT keys in `addressLookupTables`.

***

## Simulation & price checking

By default, all quotes are **simulated before being returned** to verify they execute correctly against current on-chain state. This gives **more reliable execution and tighter realized slippage** — the server has already confirmed the route works with the latest account data. Setting `simulate=false` disables this — **significantly reducing latency** by removing an entire round of RPC calls, at the cost of that pre-flight check.

To safeguard quotes without simulations, the server subscribes to **reference prices** for the requested tokens and checks that returned quotes are within a reasonable range. The `maxPriceDeviationBps` parameter controls this threshold:

* **Default (`1000` / 10%)** — Quotes must provide at least 90% of the expected value based on reference rates. Tuned to reject clearly bad quotes without being overly restrictive.
* **`10000` or higher (≥ 100%)** — Price checking is **disabled entirely**.

{% hint style="info" %}
To avoid adding latency, the price check **fails open** — if the server doesn't have up-to-date price data for both tokens (e.g. the first time a particular token is quoted), quotes are passed through without checking.
{% endhint %}

***

## Response

**The response body is MessagePack-encoded.** Set `Accept: application/vnd.msgpack` in your request headers.

The response is a [`SwapQuotes`](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md#stream-updates) object — **the same type returned by Titan Direct stream updates.** It contains a `quotes` map keyed by provider ID where each value is a [`SwapRoute`](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md#stream-updates) with instructions and address lookup table keys.

When `includeAltContents=true`, the top-level [`alts`](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md#alt-contents) array contains the full Address Lookup Table accounts used by the returned routes. This removes the need to fetch each table separately before compiling the transaction.

{% hint style="warning" %}
**`quotes` is a map, not an array.** Not every provider appears in every response — iterate with `Object.entries`.
{% endhint %}

### `metadata.ExpectedWinner`

The response includes a `metadata` object with an `ExpectedWinner` field — **this is Titan's recommendation for the best slippage-adjusted route.**

```json
{
  "metadata": {
    "ExpectedWinner": "Titan-DART"
  },
  "quotes": { ... }
}
```

Rather than sorting quotes by raw `outAmount` (which doesn't account for slippage, execution quality, or on-chain conditions), **use `metadata.ExpectedWinner` to select the route Titan expects to deliver the best actual execution.** The winner is determined by Titan's routing engine after factoring in simulation results, slippage estimates, and route reliability.

***

## Example

```typescript
import { Decoder } from '@msgpack/msgpack';

// useBigInt64 required — amounts and timestamps are u64
const decoder = new Decoder({ useBigInt64: true });

// 1 SOL → USDC swap quote
const params = new URLSearchParams({
  inputMint: 'So11111111111111111111111111111111111111112',   // SOL
  outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
  amount: '1000000000',          // 1 SOL in lamports
  userPublicKey: 'YOUR_WALLET_PUBLIC_KEY',
  slippageBps: '50',             // 0.5% slippage tolerance
});

// Request swap quotes from Gateway
const res = await fetch(
  `${process.env.TITAN_ENDPOINT}/api/v1/quote/swap?${params}`,
  {
    headers: {
      'Authorization': `Bearer ${process.env.TITAN_API_KEY}`,
      'Accept': 'application/vnd.msgpack', // Required for MessagePack response
    },
  }
);

if (!res.ok) {
  throw new Error(`${res.status}: ${res.statusText}`);
}

// Decode the MessagePack response
const buffer = await res.arrayBuffer();
const quotes = decoder.decode(new Uint8Array(buffer)) as any;

// Use metadata.ExpectedWinner to pick the best slippage-adjusted route
const winner = quotes.metadata?.ExpectedWinner;
const route = winner && quotes.quotes[winner];

if (route?.instructions?.length) {
  console.log(`Best route: ${winner} — ${route.outAmount} out`);
  // route.instructions and route.addressLookupTables are ready for transaction building
}
```

***

## Error responses

* **`400`** — **Invalid parameters.** Malformed pubkey, missing required field, or value out of bounds.
* **`401`** — **Missing or invalid authentication token.** Check your JWT and its claims.
* **`404`** — **No routes found** for this swap pair. Try relaxing routing constraints (`dexes`, `excludeDexes`, `onlyDirectRoutes`).

***

## Related pages

* [NewSwapQuoteStream](/titan/developer-doc/swap-api/reference/direct/new-swap-quote-stream.md) — Direct (WebSocket) equivalent with real-time streaming updates and full `SwapQuotes` / `SwapRoute` type definitions
* [Quote Price](/titan/developer-doc/swap-api/reference/gateway/gateway-quote-price.md) — Lightweight price-only endpoint without transaction instructions
* [Fee Collection](/titan/developer-doc/swap-api/guides/fee-collection.md) — Collect platform fees on swaps using `feeAccount` and `feeBps`
* [Configure Routing](/titan/developer-doc/swap-api/guides/configure-routing.md) — Venue and provider filtering strategies
