# 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**.
* **`providers`** — Comma-separated provider IDs. See [ListProviders](/titan/developer-doc/swap-api/reference/gateway/gateway-info.md#providers) for valid IDs.
* **`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.**

***

## 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 tables.

{% 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://titan-exchange.gitbook.io/titan/developer-doc/swap-api/reference/gateway/gateway-quote-swap.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
