# Swaps (Jupiter / Titan)

> Canonical: https://docs.velocity.exchange/developers/velocity-sdk/swaps

A spot swap can route through Jupiter or Titan directly from a Velocity account. The SDK fetches a quote from the chosen provider, builds the swap transaction, and wraps it in `begin_swap` and `end_swap` so the input and output tokens move through the account's Velocity spot balances inside one atomically-checked transaction.

> **Info:**
>
> This is a **collateral swap** between two spot balances inside a Velocity account, unrelated to spot order placement. Velocity [removed spot DLOB trading](/developers/velocity-sdk/dlob.md) entirely, so `place_spot_order` and its siblings no longer exist, but swapping the tokens backing those spot balances through an aggregator is a separate path that remains supported.

## Choosing a swap client

`UnifiedSwapClient` is the interface to build against. It wraps either Jupiter or Titan behind one API, so switching providers is a constructor change rather than a call-site change.

  
```js
import { Connection } from "@solana/web3.js";
import { UnifiedSwapClient } from "@velocity-exchange/sdk";

const connection = new Connection("<RPC_URL>", "confirmed");

// clientType: 'jupiter' | 'titan'
const swapClient = new UnifiedSwapClient({
  clientType: "jupiter",
  connection,
  authToken: "<JUPITER_API_KEY_OR_TITAN_AUTH_TOKEN>", // Jupiter: API key (portal.jup.ag). Titan: auth token (not needed behind a proxy)
});
```
  

The standalone `JupiterClient` remains available. It and `TitanClient` implement the same `SwapProvider` interface as `UnifiedSwapClient`, so a raw `JupiterClient` still works wherever `swapClient` is accepted. That path exists for backward compatibility; new integrations should use `UnifiedSwapClient`.

  
```js
import { Connection } from "@solana/web3.js";
import { JupiterClient } from "@velocity-exchange/sdk";

const connection = new Connection("<RPC_URL>", "confirmed");
const jupiterClient = new JupiterClient({ connection });
```
  

## Jupiter Swap API v1 versus v2

`JupiterClient` takes an `apiVersion` of `'v1'` or `'v2'`. It **defaults to `'v1'`**. `UnifiedSwapClient` forwards the same choice as `jupiterApiVersion` (ignored when `clientType` is `'titan'`).

| | `'v1'` (default) | `'v2'` |
|---|---|---|
| Endpoints | `GET /swap/v1/quote`, then `POST /swap/v1/swap` | `GET /swap/v2/build` only |
| Round trips per swap | Two, plus deserializing the returned transaction | One, the quote carries the route instructions |
| `userPublicKey` on `getQuote` | Optional | **Required**, v2 builds for a named taker |
| `autoSlippage` | Supported | Rejected, `getQuote` throws |
| `swapMode` | `'ExactIn'` or `'ExactOut'` | `'ExactIn'` only, anything else throws |
| `onlyDirectRoutes` | Supported | Rejected, `getQuote` throws |

  
```js
import { JupiterClient, UnifiedSwapClient } from "@velocity-exchange/sdk";

// Opt into v2 on the standalone client
const jupiterV2 = new JupiterClient({
  connection,
  apiKey: "<JUPITER_API_KEY>",
  apiVersion: "v2",
});

// Or through the unified client
const swapClient = new UnifiedSwapClient({
  clientType: "jupiter",
  connection,
  authToken: "<JUPITER_API_KEY>",
  jupiterApiVersion: "v2",
});
```
  

> **Warning:**
>
> The v2 rejections are deliberate. Jupiter's `/swap/v2/build` answers `200` for `autoSlippage`, `onlyDirectRoutes`, and `ExactOut` while ignoring them: auto-slippage comes back with zero slippage tolerance (any adverse move reverts the swap), direct-only still returns multi-hop routes, and `ExactOut` comes back as `ExactIn` with the requested amount spent as the input, which inverts the trade. The SDK throws instead of passing those through. Any of the three requires a client constructed with `apiVersion: 'v1'`.

> **Info:**
>
> The Rust SDK (`velocity-rs`) is **v2 only**. Its Jupiter path has no v1 mode and no version toggle: `jupiter_swap_query` has no `swap_mode`, `transaction_config`, or `only_direct_routes` parameters, and it takes `max_accounts: Option<usize>` (defaulting to 50) as the remaining routing lever. Rust consumers get the v2 behavior described above whether or not they opt in.

## Getting a quote

Preview the expected output and the route before committing to it. `UnifiedSwapClient.getQuote()` normalizes the request across both providers. Titan requires `userPublicKey`, and so does Jupiter's v2 API; Jupiter v1, the default, ignores it.

  
```js
const quote = await swapClient.getQuote({
  inputMint: usdtMint,    // PublicKey
  outputMint: solMint,    // PublicKey
  amount: velocityClient.convertToSpotPrecision(0, 10), // 10 USDT, BN
  slippageBps: 50,
  userPublicKey: velocityClient.wallet.publicKey, // required for Titan, and for Jupiter's v2 API; ignored by Jupiter v1 (the default)
});
console.log(quote);
```
  

## Executing the swap

`VelocityClient.swap()` takes a `swapClient`, resolves the route (using a `quote` passed in, or fetching one), and sends the transaction so the tokens move in and out of the account's Velocity spot balances.

  
```js
// Assumes `velocityClient` is subscribed.
const txSig = await velocityClient.swap({
  swapClient,
  inMarketIndex: 0,  // e.g. USDT (spot market index)
  outMarketIndex: 1, // e.g. SOL (spot market index)
  amount: velocityClient.convertToSpotPrecision(0, 10), // 10 USDT
  slippageBps: 50,         // 0.5% max slippage
  onlyDirectRoutes: false, // allow multi-hop routes for better pricing
});

console.log(txSig);
```
  

**Parameters:**

| Parameter | Description | Optional | Default |
|---|---|---|---|
| `swapClient` | `UnifiedSwapClient` (preferred), or a raw `JupiterClient`/`TitanClient` for the deprecated legacy path | No | |
| `inMarketIndex` | Velocity spot market index for the input token | No | |
| `outMarketIndex` | Velocity spot market index for the output token | No | |
| `amount` | Amount to swap as a BN, spot market precision | No | |
| `slippageBps` | Maximum allowed slippage in basis points | Yes | 50 |
| `swapMode` | `'ExactIn'` or `'ExactOut'` | Yes | `'ExactIn'` |
| `onlyDirectRoutes` | If true, restricts to direct token pairs only (no multi-hop) | Yes | false |
| `reduceOnly` | `SwapReduceOnly`: constrain the in/out token balance to reduce-only at swap end | Yes | |
| `quote` | Pre-fetched quote (from `getQuote()`) to skip an extra round-trip | Yes | |
| `txParams` | Compute-unit/priority-fee overrides | Yes | |

> **Info:**
>
> `TitanClient` itself is an internal implementation detail and is not exported from the SDK root: construct Titan-backed swaps through `new UnifiedSwapClient({ clientType: "titan", ... })` rather than importing `TitanClient` directly.
