> 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/direct/new-swap-quote-stream.md).

# NewSwapQuoteStream

Open a streaming swap quote that updates continuously as on-chain state changes.

**Opens a stream of live swap quotes.** The server responds with a stream ID and begins pushing [`StreamData`](/titan/developer-doc/swap-api/reference/types.md#message-envelope-types) messages at the configured interval until the stream is [stopped](/titan/developer-doc/swap-api/reference/direct/stop-stream.md) or the connection closes.

## Request

The request is a `SwapQuoteRequest` with three sub-objects: `swap` (what to quote), `transaction` (wallet context for building instructions), and `update` (optional stream tuning).

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

```rust
struct SwapQuoteRequest {
  /// Parameters for the swap.
  swap: SwapParams,
  /// Parameters for transaction generation.
  transaction: TransactionParams,
  /// Parameters for the stream of quote updates.
  update: Option<QuoteUpdateParams>,
}

struct SwapParams {
  /// Address of the input mint of the swap.
  inputMint: Pubkey,
  /// Address of the desired output token for the swap.
  outputMint: Pubkey,
  /// Raw number of tokens to swap, not scaled by decimals.
  amount: u64,
  /// Swap mode for how the amount should be interpreted.
  /// Either ExactIn or ExactOut, defaults to ExactIn.
  swapMode: Option<SwapMode>,
  /// Allowed slippage in basis points.
  slippageBps: Option<u16>,
  /// If set, constrain quotes to the given set of DEXes.
  dexes: Option<Vec<String>>,
  /// If set, exclude the following DEXes when determining routes.
  excludeDexes: Option<Vec<String>>,
  /// If true, exclude a server-configured set of market-maker venues from
  /// routing. Included as normal when absent or false.
  noVoteAccounts: Option<bool>,
  /// If set to true, only direct routes between the input and output mint
  /// will be considered.
  onlyDirectRoutes: Option<bool>,
  /// If set to true, only quotes with transactions that fit within the size
  /// constraint are returned.
  addSizeConstraint: Option<bool>,
  /// The size constraint to use when `addSizeConstraint` is set.
  /// Default is set by the server, normally slightly less than the maximum
  /// for the requested transaction format. Values above the format maximum
  /// are clamped: 1232 bytes for V0 and 4096 bytes for V1.
  sizeConstraint: Option<u32>,
  /// If set, limit quotes to the given set of provider IDs.
  providers: Option<Vec<String>>,
  /// If set, constrain quotes to routes that only use venues (pools) whose
  /// address is in this list. Filters by individual venue address, unlike
  /// `dexes`/`excludeDexes` which filter by venue label.
  venueAllowlist: Option<Vec<Pubkey>>,
  /// If set, exclude any route that uses a venue (pool) whose address is in
  /// this list. The banlist overrides `venueAllowlist`: a venue in both lists
  /// is always excluded.
  venueBanlist: Option<Vec<Pubkey>>,
  /// If set, limit total number of accounts used by routes.
  /// V1 supports at most 64 addresses; higher values are clamped.
  accountsLimitTotal: Option<u16>,
  /// If set, limit total number of writable accounts used by routes.
  /// If not set, up to 64 writable accounts are allowed.
  accountsLimitWritable: Option<u16>,
  /// A template of instructions and ALTs the router must leave room for in
  /// the transaction. Titan generates a swap that fits alongside them within
  /// Solana's size limits. See "Transaction Template" below.
  /// INCOMPATIBLE with `accountsLimitTotal`, `accountsLimitWritable`, and
  /// `sizeConstraint` — passing both returns an error.
  transactionTemplate: Option<TransactionTemplate>,
}

struct TransactionParams {
  /// Public key of the user requesting the swap.
  /// NOTE: Setting this to a read-only system account will result in
  /// simulations failing and no quotes being returned.
  userPublicKey: Pubkey,
  /// If true, close the input token account as part of the transaction.
  closeInputTokenAccount: Option<bool>,
  /// If true, an idempotent ATA will be added to the transactions.
  createOutputTokenAccount: Option<bool>,
  /// Token account for the output mint used to collect fees.
  /// Must already exist on-chain.
  feeAccount: Option<Pubkey>,
  /// Fee amount to take, in basis points.
  /// If not specified, default fee for the requester is used.
  feeBps: Option<u16>,
  /// Whether the fee should be taken in terms of the input mint.
  /// Default is false (fee taken from output mint).
  feeFromInputMint: Option<bool>,
  /// Token account into which to place the output of the swap.
  /// If not specified, the user's ATA is used.
  outputAccount: Option<Pubkey>,
  /// If true, leave the output as wrapped SOL (the wSOL SPL token) instead of
  /// unwrapping it to native SOL. Only has an effect when the output mint is
  /// wSOL; ignored otherwise. Default: false (output unwrapped to native SOL).
  /// Requires `titanSwapVersion: 3`.
  outputWsol: Option<bool>,
  /// Router version to use: `3` for V3, otherwise V2. See "Swap V3" below.
  titanSwapVersion: Option<u8>,
  /// Solana transaction wire format Titan should use when sizing routes.
  /// Defaults to V0. V1 requires Titan Swap V3.
  transactionFormat: Option<TransactionFormat>,
  /// Separate funder for 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`.
  payer: Option<Pubkey>,
  /// 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 output mint — passing a wallet pubkey
  /// or wrong-mint token account fails the transaction at execution.
  /// Requires `titanSwapVersion: 3`.
  positiveSlippageFeeReceiver: Option<Pubkey>,
}

struct QuoteUpdateParams {
  /// How often the server should send updates, in milliseconds.
  intervalMs: Option<u64>,
  /// Maximum number of quotes per update.
  /// If more are available, the worst are filtered out.
  numQuotes: Option<u32>,
  /// Whether to include Address Lookup Table contents in responses.
  /// If omitted, only ALT addresses are returned and the client must fetch
  /// each table when building the transaction.
  includeAltContents: Option<bool>,
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
interface SwapQuoteRequest {
  // Parameters for the swap.
  swap: SwapParams;
  // Parameters for transaction generation.
  transaction: TransactionParams;
  // Parameters for the stream of quote updates.
  update?: QuoteUpdateParams;
}

interface SwapParams {
  // Address of input mint for the swap.
  inputMint: Pubkey;
  // Address of output mint of the swap.
  outputMint: Pubkey;
  // Raw number of tokens to swap, not scaled by decimals.
  amount: number;
  // Whether amount is in terms of inputMint or outputMint.
  // Defaults to ExactIn.
  swapMode?: SwapMode;
  // Maximum allowed slippage, in basis points.
  slippageBps?: number;
  // If set, constrain quotes to the given set of DEXes.
  dexes?: string[];
  // If set, exclude the following DEXes when determining routes.
  excludeDexes?: string[];
  // If true, exclude a server-configured set of market-maker venues from
  // routing. Included as normal when absent or false.
  noVoteAccounts?: boolean;
  // If true, only direct routes will be considered.
  onlyDirectRoutes?: boolean;
  // If true, only quotes that fit within the size constraint are returned.
  addSizeConstraint?: boolean;
  // The size constraint to use when `addSizeConstraint` is set.
  // Default is set by the server, normally slightly less than the maximum
  // for the requested transaction format. Values above the format maximum
  // are clamped: 1232 bytes for V0 and 4096 bytes for V1.
  sizeConstraint?: number;
  // If set, limit quotes to the given set of provider IDs.
  providers?: string[];
  // Constrain quotes to routes that only use venues (pools) whose address is
  // in this list. Filters by individual venue address, unlike
  // `dexes`/`excludeDexes` which filter by venue label.
  venueAllowlist?: Pubkey[];
  // Exclude any route that uses a venue (pool) whose address is in this list.
  // The banlist overrides `venueAllowlist`: a venue in both lists is always
  // excluded.
  venueBanlist?: Pubkey[];
  // Max total accounts per route. V1 supports at most 64 addresses.
  accountsLimitTotal?: number;
  // Max writable accounts per route. Default: 64.
  accountsLimitWritable?: number;
  // A template of instructions and ALTs the router must leave room for in
  // the transaction. Titan generates a swap that fits alongside them within
  // Solana's size limits. See "Transaction Template" below.
  // INCOMPATIBLE with `accountsLimitTotal`, `accountsLimitWritable`, and
  // `sizeConstraint` — passing both returns an error.
  transactionTemplate?: TransactionTemplate;
}

interface TransactionParams {
  // Public key of the user requesting the swap.
  // NOTE: Setting this to a read-only system account will result in
  // simulations failing and no quotes being returned.
  userPublicKey: Pubkey;
  // If true, close the input token account as part of the transaction.
  closeInputTokenAccount?: boolean;
  // If true, an idempotent ATA creation is added to the transaction.
  createOutputTokenAccount?: boolean;
  // Token account for collecting fees. Must already exist on-chain.
  feeAccount?: Pubkey;
  // Fee amount in basis points. If not specified, default fee is used.
  feeBps?: number;
  // If true, fee is taken from input mint. Default: false (output mint).
  feeFromInputMint?: boolean;
  // Custom output token account. Defaults to the user's ATA.
  outputAccount?: Pubkey;
  // If true, leave the output as wrapped SOL (the wSOL SPL token) instead of
  // unwrapping it to native SOL. Only has an effect when the output mint is
  // wSOL; ignored otherwise. Default: false (output unwrapped to native SOL).
  // Requires `titanSwapVersion: 3`.
  outputWsol?: boolean;
  // Router version to use: `3` for V3, otherwise V2. See "Swap V3" below.
  titanSwapVersion?: number;
  // Solana transaction wire format Titan should use when sizing routes.
  // Defaults to V0. V1 requires Titan Swap V3.
  transactionFormat?: TransactionFormat;
  // Separate funder for 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`.
  payer?: Pubkey;
  // 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 output mint — passing a wallet pubkey
  // or wrong-mint token account fails the transaction at execution.
  // Requires `titanSwapVersion: 3`.
  positiveSlippageFeeReceiver?: Pubkey;
}

interface QuoteUpdateParams {
  // How often the server should send updates, in milliseconds.
  intervalMs?: number;
  // Maximum number of quotes per update.
  numQuotes?: number;
  // Whether to include Address Lookup Table contents in responses.
  // If omitted, only ALT addresses are returned and the client must fetch
  // each table when building the transaction.
  includeAltContents?: boolean;
}
```

{% endtab %}
{% endtabs %}

## Response

A successful response includes a [`QuoteSwapStreamResponse`](/titan/developer-doc/swap-api/reference/types.md) with the confirmed update interval, and a [`StreamStart`](/titan/developer-doc/swap-api/reference/types.md#message-envelope-types) with the stream ID:

* **`intervalMs`** (`u64`) — The actual interval the server will use for this stream.
* **`stream.id`** (`u32`) — **Use this ID to** [**stop the stream**](/titan/developer-doc/swap-api/reference/direct/stop-stream.md) **later.**
* **`stream.dataType`** — Always `"SwapQuotes"`.

## Stream updates

After the stream opens, the server pushes `StreamData` messages at the confirmed interval. Each contains a `SwapQuotes` payload — **a `quotes` map keyed by provider ID** where each value is a `SwapRoute` with quote details and executable instructions.

### `metadata.ExpectedWinner`

Each `SwapQuotes` update includes a `metadata` object with an `ExpectedWinner` field — **Titan's recommendation for the best slippage-adjusted route.** Rather than sorting by raw `outAmount`, use this to select the route that Titan expects to deliver the best actual execution after factoring in slippage, simulation results, and route reliability.

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

```rust
struct SwapQuotes {
  /// Unique identifier for the quote.
  id: String,
  /// Address of the input mint for this quote.
  inputMint: Pubkey,
  /// Address of the output mint for this quote.
  outputMint: Pubkey,
  /// What swap mode was used for the quotes.
  swapMode: SwapMode,
  /// Amount used for the quotes.
  amount: u64,
  /// A mapping of a provider identifier to their quoted route.
  quotes: HashMap<String, SwapRoute>,
  /// Metadata including the expected winning provider (when DART is enabled).
  metadata: Option<SwapQuotesMetadata>,
  /// Contents of Address Lookup Tables used by the returned routes, if requested.
  /// Available since v1.9.
  alts: Option<Vec<AddressLookupTableAccount>>,
}

struct SwapQuotesMetadata {
  /// The provider Titan expects to deliver the best slippage-adjusted execution.
  ExpectedWinner: Option<String>,
}

struct SwapRoute {
  /// How many input tokens go through this route.
  inAmount: u64,
  /// How many output tokens are expected.
  outAmount: u64,
  /// Slippage incurred, in basis points.
  slippageBps: u16,
  /// Platform fee information, if a fee is charged.
  platformFee: Option<PlatformFee>,
  /// Steps that comprise this route.
  steps: Vec<RoutePlanStep>,
  /// Instructions needed to execute the route.
  /// May not be provided if a full transaction is provided instead.
  instructions: Vec<Instruction>,
  /// Address lookup tables necessary to load.
  addressLookupTables: Vec<Pubkey>,
  /// Context slot for the route.
  contextSlot: Option<u64>,
  /// Time taken to generate the quote in nanoseconds.
  timeTakenNs: Option<u64>,
  /// If this route expires by time, millisecond UNIX timestamp.
  expiresAtMs: Option<u64>,
  /// If this route expires by slot, last valid slot.
  expiresAfterSlot: Option<u64>,
  /// Compute units this transaction is expected to consume.
  computeUnits: Option<u64>,
  /// Recommended compute unit budget.
  /// Higher than computeUnits to account for on-chain fluctuations.
  computeUnitsSafe: Option<u64>,
  /// Transaction for the user to sign, if instructions are not provided.
  transaction: Option<Vec<u8>>,
  /// Provider-specific reference ID for this quote.
  /// Mainly provided by RFQ-based providers.
  reference_id: Option<String>,
}

struct RoutePlanStep {
  /// Which AMM is being executed on at this step.
  ammKey: Pubkey,
  /// Label for the protocol (e.g. "Raydium AMM", "Phoenix").
  label: String,
  /// Input mint for this step.
  inputMint: Pubkey,
  /// Output mint for this step.
  outputMint: Pubkey,
  /// Input tokens expected to go through this step.
  inAmount: u64,
  /// Output tokens expected from this step.
  outAmount: u64,
  /// Proportion of order flow in parts per billion.
  allocPpb: u32,
  /// Mint of the fee token, if applicable.
  feeMint: Option<Pubkey>,
  /// Fee amount charged by the venue.
  feeAmount: Option<u64>,
  /// Context slot for the pool data.
  contextSlot: Option<u64>,
}

struct PlatformFee {
  /// Amount of tokens taken as a fee.
  amount: u64,
  /// Fee percentage, in basis points.
  fee_bps: u8,
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
interface SwapQuotes {
  // Unique Quote identifier.
  id: string;
  // Address of the input mint.
  inputMint: Uint8Array;
  // Address of the output mint.
  outputMint: Uint8Array;
  // What swap mode was used.
  swapMode: SwapMode;
  // Amount used for the quotes.
  amount: number;
  // A mapping of provider identifier to their quoted route.
  quotes: { [key: string]: SwapRoute };
  // Contents of Address Lookup Tables used by the returned routes, if requested.
  // Available since v1.9.
  alts?: AddressLookupTableAccount[];
}

interface SwapRoute {
  // Input tokens going through this route.
  inAmount: number;
  // Expected output tokens.
  outAmount: number;
  // Slippage incurred, in basis points.
  slippageBps: number;
  // Platform fee information, if charged.
  platformFee?: PlatformFee;
  // Steps that comprise this route.
  steps: RoutePlanStep[];
  // Instructions needed to execute the route.
  instructions: Instruction[];
  // Address lookup tables necessary to load.
  addressLookupTables: Pubkey[];
  // Context slot for the route.
  contextSlot?: number;
  // Time taken to generate the quote in nanoseconds.
  timeTaken?: number;
  // If this route expires by time, millisecond UNIX timestamp.
  expiresAtMs?: number;
  // If this route expires by slot, last valid slot.
  expiresAfterSlot?: number;
  // Compute units this transaction is expected to consume.
  computeUnits?: number;
  // Recommended compute unit budget.
  computeUnitsSafe?: number;
  // Transaction for the user to sign, if instructions not provided.
  transaction?: Uint8Array;
  // Provider-specific reference ID for this quote.
  referenceId?: string;
}

interface RoutePlanStep {
  // Which AMM is being executed on at this step.
  ammKey: Uint8Array;
  // Label for the protocol (e.g. "Raydium AMM", "Phoenix").
  label: string;
  // Input mint for this step.
  inputMint: Uint8Array;
  // Output mint for this step.
  outputMint: Uint8Array;
  // Input tokens expected to go through this step.
  inAmount: number;
  // Output tokens expected from this step.
  outAmount: number;
  // Proportion of order flow in parts per billion.
  allocPpb: number;
  // Mint of the fee token, if applicable.
  feeMint?: Uint8Array;
  // Fee amount charged by the venue.
  feeAmount?: number;
  // Context slot for the pool data.
  contextSlot?: number;
}

interface PlatformFee {
  // Amount of tokens taken as a fee.
  amount: number;
  // Fee percentage, in basis points.
  fee_bps: number;
}
```

{% endtab %}
{% endtabs %}

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

### ALT contents

Set `update.includeAltContents` to `true` to include the full Address Lookup Table accounts used by the returned routes. The `SwapQuotes.alts` array contains compact `AddressLookupTableAccount` values: `p` is the table's 32-byte public key and `a` is its ordered array of 32-byte addresses. Match `p` against the keys in a route's `addressLookupTables` array when compiling its transaction.

If you omit `includeAltContents` or set it to `false`, `alts` is omitted. Each route still returns `addressLookupTables`, but you must fetch those accounts before building the transaction.

## Transaction format

`transaction.transactionFormat` selects the Solana transaction wire format Titan uses when sizing candidate routes. It is separate from `titanSwapVersion`, which selects the Titan swap instruction version.

| Value | SDK enum               | Format                                                                                                                                               | Maximum size | Address lookup tables |
| ----- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -----------: | --------------------- |
| `0`   | `TransactionFormat.V0` | Versioned v0 transaction                                                                                                                             |   1232 bytes | Supported             |
| `1`   | `TransactionFormat.V1` | Agave 4.2 Transaction V1 ([SIMD-0385](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md)) |   4096 bytes | Not supported         |

V0 is the default. V1 writes every account as a full 32-byte address and supports at most 64 addresses, so account count usually limits a V1 route before transaction size does.

{% hint style="warning" %}
**Transaction V1 requires the Agave 4.2 feature set to be active on the cluster where you submit the transaction.** Titan uses `transactionFormat` for route sizing but does not verify cluster activation. Keep using V0 until activation is confirmed for your target cluster.
{% endhint %}

`transactionFormat` is encoded as its numeric value. Send `1`, not `"V1"`. V1 also requires Titan Swap V3: set `titanSwapVersion: 3`, or omit `titanSwapVersion` and let the server resolve it to V3. An explicit V1 + Swap V2 request is rejected.

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

```rust
enum TransactionFormat {
  V0 = 0,
  V1 = 1,
}

struct TransactionConfigParams {
  /// Priority fee in lamports.
  priorityFee: Option<u64>,
  /// Maximum compute units.
  computeUnitLimit: Option<u32>,
  /// Maximum bytes of account data that may be loaded.
  loadedAccountsDataSizeLimit: Option<u32>,
  /// Requested heap size in bytes. Must be a multiple of 1024.
  heapSize: Option<u32>,
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
enum TransactionFormat {
  V0 = 0,
  V1 = 1,
}

interface TransactionConfigParams {
  // Priority fee in lamports.
  priorityFee?: number;
  // Maximum compute units.
  computeUnitLimit?: number;
  // Maximum bytes of account data that may be loaded.
  loadedAccountsDataSizeLimit?: number;
  // Requested heap size in bytes. Must be a multiple of 1024.
  heapSize?: number;
}
```

{% endtab %}
{% endtabs %}

Transaction V1 carries priority-fee and compute-budget settings in the transaction envelope instead of `ComputeBudgetProgram` instructions. Each configured field adds 4 bytes to the transaction, except `priorityFee`, which adds 8 bytes. An omitted field uses the runtime default.

## Transaction Template

`transactionTemplate` lets you reserve room in the transaction for instructions and address lookup tables that you plan to prepend or append yourself — a custom fee transfer, an oracle update, an app-specific log, etc. Titan factors the template into route sizing so the final transaction still fits within Solana's limits.

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

```rust
struct TransactionTemplate {
  /// Instructions to reserve space for. It is assumed that you have
  /// included the input mint and output mint account creation/deletion
  /// instructions when necessary.
  i: Vec<Instruction>,
  /// Address lookup tables used in the instructions. Provide them in the
  /// same order you'll use when compiling the message — Solana uses ALTs
  /// greedily, so their effect depends on ordering. Titan extends this
  /// vector with any ALTs it uses for the swap.
  a: Vec<AddressLookupTableAccount>,
  /// Additional account metas to include in sizing calculations.
  m: Vec<AccountMeta>,
  /// Transaction-level configuration. Required for V1; ignored for V0.
  c: Option<TransactionConfigParams>,
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
interface TransactionTemplate {
  // Instructions to reserve space for. It is assumed that you have
  // included the input mint and output mint account creation/deletion
  // instructions when necessary.
  i: Instruction[];
  // Address lookup tables used in the instructions. Provide them in the
  // same order you'll use when compiling the message — Solana uses ALTs
  // greedily, so their effect depends on ordering. Titan extends this
  // array with any ALTs it uses for the swap.
  a: AddressLookupTableAccount[];
  // Additional account metas to include in sizing calculations.
  m: AccountMeta[];
  // Transaction-level configuration. Required for V1; ignored for V0.
  c?: TransactionConfigParams;
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**`transactionTemplate` is incompatible with `accountsLimitTotal`, `accountsLimitWritable`, and `sizeConstraint`.** The template is the sizing constraint — passing both returns an error.
{% endhint %}

{% hint style="warning" %}
When `transactionFormat` is V1, `c` is required because the compute budget is part of the transaction envelope. The `a` field is ignored because Transaction V1 does not support address lookup tables.
{% endhint %}

{% hint style="info" %}
**Wire format uses single-letter field names for space efficiency.** Each `Instruction` serializes as `{ p, a, d }` (programId / accounts / data), each `AccountMeta` as `{ p, s, w }` (pubkey / isSigner / isWritable), each `AddressLookupTableAccount` as `{ p, a }` (key / addresses). Pubkeys are raw 32-byte arrays, not Base58 strings. See the [Transaction Template guide](/titan/developer-doc/swap-api/guides/transaction-template.md) for a worked example.
{% endhint %}

## Swap V3

Swap V3 is the newer routing version of the Titan Exchange Router (`T1TANpTeScyeqVzzgNViGDNrkQ6qHz9KrSBS4aNXvGT`). Opt in by setting `titanSwapVersion: 3` in `TransactionParams` — this unlocks the `payer`, `positiveSlippageFeeReceiver`, and `outputWsol` fields.

Titan returns V3 by default. Set `titanSwapVersion: 2` to keep using V2; the V3-only fields are unavailable when V2 is selected.

```json
{
  "transaction": {
    "userPublicKey": "72neGwRAi6QWsFQjy3PkDuYBC5GNCRwC2aUMGcrkoJuP",
    "titanSwapVersion": 3,
    "payer": "Gb4WdRjp7orviHSRz88pa3y9UkArLHR4gWWSv5HP31ZW",
    "positiveSlippageFeeReceiver": "LzEWGGE7aGC3XVqmMhiTZsByJBhr16dJpJoNY5RuWQ5"
  }
}
```

## Example

```typescript
import bs58 from 'bs58';

// Pubkeys are 32-byte binary — decode from Base58 before sending
const SOL  = bs58.decode('So11111111111111111111111111111111111111112');
const USDC = bs58.decode('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const userPublicKey = bs58.decode('YOUR_WALLET_PUBLIC_KEY');

// Open a swap quote stream — server will push updates at the configured interval
await sendRequest(ws, requestId++, {
  NewSwapQuoteStream: {
    swap: {
      inputMint: SOL,
      outputMint: USDC,
      amount: 1_000_000_000n, // 1 SOL in lamports — must be BigInt
      slippageBps: 50,        // 0.5% slippage tolerance
    },
    transaction: {
      userPublicKey,           // Needed for transaction/instruction generation
    },
  },
});

// Track the stream ID so we can stop it later
let streamId: number | undefined;

ws.on('message', async (raw: Buffer) => {
  const msg = await decodeMessage(raw);

  // Stream opened — capture the stream ID and confirmed interval
  if ('Response' in msg && 'NewSwapQuoteStream' in msg.Response.data) {
    streamId = msg.Response.stream.id;
    console.log(`Stream ${streamId} open — interval: ${msg.Response.data.NewSwapQuoteStream.intervalMs}ms`);
  }

  // Quote update — quotes is a map keyed by provider ID, not an array
  if ('StreamData' in msg) {
    const quotes = msg.StreamData.payload.SwapQuotes;
    for (const [provider, route] of Object.entries(quotes.quotes as Record<string, any>)) {
      if (route.instructions?.length) {
        console.log(`${provider}: ${route.outAmount} out`);
      }
    }
  }

  // RPC error — check code and message for details
  if ('Error' in msg) {
    console.error(`Error ${msg.Error.code}: ${msg.Error.message}`);
  }

  // Stream closed — check errorCode/errorMessage if present
  if ('StreamEnd' in msg) {
    console.log(`Stream ${msg.StreamEnd.id} ended`);
    ws.close();
  }
});
```

See [Connection & Negotiation](/titan/developer-doc/swap-api/reference/direct/connection.md#sending-a-request) for `sendRequest` and `decodeMessage` setup.

***

## Related pages

* [StopStream](/titan/developer-doc/swap-api/reference/direct/stop-stream.md) — stop an active stream by its ID
* [Stream & Execute a Swap](/titan/developer-doc/swap-api/guides/stream-and-execute.md) — full guide with transaction building, signing, and error handling
* [Configure Routing](/titan/developer-doc/swap-api/guides/configure-routing.md) — venue and provider filtering
* [Fee Collection](/titan/developer-doc/swap-api/guides/fee-collection.md) — collect platform fees on swaps
* [Types Reference](/titan/developer-doc/swap-api/reference/types.md) — `SwapQuoteRequest`, `SwapRoute`, `SwapQuotes`, and all type definitions
