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

# Build and send Solana swaps with Raptor

> Swap tokens from a browser wallet with Raptor: quote, build, sign, send and track. Also covers building your own transaction from instructions and streaming ready-to-sign swaps.

This guide shows a browser swap flow from start to finish, then two variations: building the transaction yourself, and streaming ready-to-sign swaps. For a server-side script, see the [Raptor quickstart](/raptor/overview#quickstart).

<Info>
  **HTTP:** `https://raptor.solanatracker.io` · **WebSocket:** `wss://raptor.solanatracker.io`. No API key needed.
</Info>

## Swap from a browser wallet

The example uses `@solana/web3.js` and any wallet that exposes `signTransaction` (Phantom, Solflare, Wallet Adapter).

```javascript theme={null}
import { VersionedTransaction } from "@solana/web3.js";

const RAPTOR = "https://raptor.solanatracker.io";

async function api(path, body) {
  const res = await fetch(`${RAPTOR}${path}`, body && {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  const text = await res.text();
  if (!res.ok) throw new Error(`${res.status}: ${text}`);
  return JSON.parse(text);
}

export async function swap(wallet, inputMint, outputMint, amount) {
  // 1. Quote
  const quote = await api(`/quote?${new URLSearchParams({
    inputMint, outputMint, amount, slippageBps: "50",
  })}`);

  // 2. Build. Send the quote back unchanged, within a few seconds.
  const { swapTransaction } = await api("/swap", {
    userPublicKey: wallet.publicKey.toBase58(),
    quoteResponse: quote,
    priorityFee: "high",
  });

  // 3. Sign in the wallet
  const tx = VersionedTransaction.deserialize(
    Uint8Array.from(atob(swapTransaction), (c) => c.charCodeAt(0))
  );
  const signed = await wallet.signTransaction(tx);

  // 4. Send
  const { signature } = await api("/send-transaction", {
    transaction: btoa(String.fromCharCode(...signed.serialize())),
  });

  // 5. Wait for the result
  for (let i = 0; i < 30; i++) {
    const result = await api(`/transaction/${signature}`);
    if (result.status !== "pending") return result; // confirmed, failed or expired
    await new Promise((r) => setTimeout(r, 1000));
  }
  throw new Error("Timed out");
}

// 0.1 SOL -> USDC
await swap(
  window.solana,
  "So11111111111111111111111111111111111111112",
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "100000000"
);
```

### Show the price before signing

If the user should confirm the price first, show the quote fields, then build the transaction once they accept. Fetch a new quote if they wait more than a few seconds.

| Field | Show it as |
| - | - |
| `amountOut` | Expected amount, in the output token's smallest unit. Divide by `10^decimals`. |
| `minAmountOut` | Least they'll receive after slippage and your platform fee |
| `priceImpact` | Already a percent: `0.25` means 0.25% |
| `routePlan[].dex` | DEXes used |

### Common options

On `/quote`:

| Option | Example | Effect |
| - | - | - |
| `slippageBps` | `100` or `dynamic` | Maximum price movement, in basis points |
| `dexes` | `raydium,meteora` | Only use these DEXes |
| `maxHops` | `2` | Shorter routes |
| `feeAccount` + `feeBps` | `25` | Take a 0.25% platform fee |

On `/swap`:

| Option | Example | Effect |
| - | - | - |
| `priorityFee` | `high` or `"50000"` | Priority level, or a total fee in lamports |
| `maxPriorityFee` | `200000` | Cap on compute unit price, in micro-lamports |
| `tipAccount` + `tipLamports` | `10000` | Add a SOL tip |
| `txVersion` | `LEGACY` | Transaction format (`V0` by default, upper-case) |
| `wrapUnwrapSol` | `false` | Turn off automatic SOL wrapping |

Raptor creates any token accounts the user is missing and wraps and unwraps SOL inside the transaction. The user pays the rent for new token accounts (about 0.002 SOL each).

## Quote and build in one call

When the user doesn't need to review the price, `POST /quote-and-swap` takes the quote parameters and the wallet together and returns both:

```javascript theme={null}
const { quote, swapTransaction } = await api("/quote-and-swap", {
  userPublicKey: wallet.publicKey.toBase58(),
  inputMint: "So11111111111111111111111111111111111111112",
  outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  amount: 100000000,
  slippageBps: "50",
  priorityFee: "high",
});
```

## Build your own transaction

Use `POST /swap-instructions` to add your own instructions, such as a memo or a transfer, around the swap. It takes the same body as `/swap`.

```javascript theme={null}
import {
  Connection, PublicKey, TransactionInstruction,
  TransactionMessage, VersionedTransaction,
} from "@solana/web3.js";

const connection = new Connection("https://rpc-mainnet.solanatracker.io/?api_key=YOUR_KEY");

const ix = await api("/swap-instructions", {
  userPublicKey: wallet.publicKey.toBase58(),
  quoteResponse: quote,
});

const toIx = (i) => new TransactionInstruction({
  programId: new PublicKey(i.programId),
  keys: i.accounts.map((a) => ({ pubkey: new PublicKey(a.pubkey), isSigner: a.isSigner, isWritable: a.isWritable })),
  data: Buffer.from(i.data, "base64"),
});

const instructions = [
  ...ix.computeBudgetInstructions,
  ...ix.setupInstructions,
  ix.swapInstruction,
  ix.cleanupInstruction,
  ix.tipInstruction,
].filter(Boolean).map(toIx);
// Add your own instructions here. If ix.topLevelOnly is true, move the swap to the end.

const lookupTables = await Promise.all(
  ix.addressLookupTableAddresses.map(async (a) => (await connection.getAddressLookupTable(new PublicKey(a))).value)
);
const { blockhash } = await connection.getLatestBlockhash();

const tx = new VersionedTransaction(new TransactionMessage({
  payerKey: wallet.publicKey,
  recentBlockhash: blockhash,
  instructions,
}).compileToV0Message(lookupTables));
```

Sign and send it as in the browser example. Two things to know:

* If the response includes `quoteResponse`, the route was rebuilt. Show the user those amounts.
* `/swap-instructions` returns an ordinary swap that you can also call from your own program through CPI. If you ask for `jitRouting: true`, the response has `topLevelOnly: true`, and the swap must be the last top-level instruction. See [JIT routing](/raptor/overview#jit-routing).

## Stream ready-to-sign swaps

`/stream/swap` sends a new quote and a freshly built transaction whenever the best route changes. When the user clicks Swap, sign the latest transaction and send it. There's no separate build step.

```javascript theme={null}
const ws = new WebSocket("wss://raptor.solanatracker.io/stream/swap");
let latest;

ws.onopen = () => ws.send(JSON.stringify({
  type: "subscribe",
  inputMint: "So11111111111111111111111111111111111111112",
  outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  amount: 100000000,
  userPublicKey: wallet.publicKey.toBase58(),
  slippageBps: "50",
  priorityFee: "high",
}));

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "swap") {
    latest = msg;
    console.log(`Now: ${msg.quote.amountOut}`);
  }
  if (msg.type === "error") console.error(msg.error);
};

async function onSwapClick() {
  const tx = VersionedTransaction.deserialize(
    Uint8Array.from(atob(latest.swapTransaction), (c) => c.charCodeAt(0))
  );
  const signed = await wallet.signTransaction(tx);
  return api("/send-transaction", {
    transaction: btoa(String.fromCharCode(...signed.serialize())),
  });
}
```

For prices only, use `/stream` instead. It takes the same subscribe message without `userPublicKey`, and its updates have `type: "quote"` with the quote in `data`.

<CardGroup cols={2}>
  <Card title="Raptor overview" href="/raptor/overview">
    Parameters, JIT routing, errors and supported DEXes.
  </Card>

  <Card title="Transactions" href="/raptor/transactions">
    Status values and reading swap results.
  </Card>
</CardGroup>


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