Swaps with Jupiter
Jupiter aggregates liquidity across Raydium, Orca, Meteora, and other Solana AMMs into a single swap API. Use it when you need best-price routing without maintaining pool graphs yourself.
Recipe
Quick-reference recipe card - copy-paste ready.
const quote = await fetch(
`https://quote-api.jup.ag/v6/quote?inputMint=${inMint}&outputMint=${outMint}&amount=${amount}&slippageBps=50`
).then((r) => r.json());
const swap = await fetch("https://quote-api.jup.ag/v6/swap", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ quoteResponse: quote, userPublicKey: wallet, wrapAndUnwrapSol: true }),
}).then((r) => r.json());When to reach for this:
- Building a wallet swap UI without curating pool lists.
- Backend rebalancing treasuries across SPL tokens.
- Routing through multiple AMM hops in one transaction.
- Getting serialized transactions for
@solana/kit7.0.0 signers.
Working Example
import { createSolanaRpc, address, lamports } from "@solana/kit";
import { getBase58Codec } from "@solana/codecs-strings";
const RPC = "https://api.mainnet-beta.solana.com";
const rpc = createSolanaRpc(RPC);
const inputMint = "So11111111111111111111111111111111111111112";
const outputMint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
const amount = "50000000"; // 0.05 SOL
const slippageBps = 50;
const userPublicKey = "YOUR_WALLET_PUBKEY";
const quote = await fetch(
`https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippageBps}`
).then((r) => r.json());
const { swapTransaction } = await fetch("https://quote-api.jup.ag/v6/swap", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
quoteResponse: quote,
userPublicKey,
wrapAndUnwrapSol: true,
dynamicComputeUnitLimit: true,
prioritizationFeeLamports: "auto",
}),
}).then((r) => r.json());
const txBytes = getBase58Codec().decode(swapTransaction);
// Sign txBytes with wallet, send via rpc.sendTransaction(...)
console.log("Expected out:", quote.outAmount);What this demonstrates:
- Quote API returns
outAmount,priceImpactPct, androutePlan. - Swap API returns a base58-encoded versioned transaction ready to sign.
dynamicComputeUnitLimitandprioritizationFeeLamportstune landing on Agave 4.1.1.
Deep Dive
How It Works
- Jupiter's router scans live pool state and builds a multi-hop route.
- The swap transaction bundles CPIs into each AMM program in route order.
- Token accounts, wSOL wrap/unwrap, and ATAs are handled in the instruction list.
- Versioned transactions may include address lookup tables for account compression.
Jupiter API Surface
| Endpoint | Purpose | Key params |
|---|---|---|
/v6/quote | Price route | inputMint, outputMint, amount, slippageBps |
/v6/swap | Build tx | quoteResponse, userPublicKey |
/v6/swap-instructions | Raw ix list | For custom tx assembly |
TypeScript Notes
// Refresh quote if blockhash ages - quotes expire quickly
const MAX_QUOTE_AGE_MS = 30_000;
const quotedAt = Date.now();
// Re-quote before send if Date.now() - quotedAt > MAX_QUOTE_AGE_MSGotchas
- Stale quotes - Routes invalidate as reserves move. Fix: Re-fetch quote immediately before
swapand set a max age window. - Slippage too low - Volatile pairs fail with
SlippageToleranceExceeded. Fix: IncreaseslippageBpsor split into smaller swaps. - Missing ATA - Output token account may not exist. Fix: Enable
createAtaoptions or pre-create ATA in a setup tx. - wSOL confusion - Native SOL and wSOL are different mints. Fix: Use
wrapAndUnwrapSol: trueor manage wSOL ATA explicitly. - Compute budget - Multi-hop routes exceed default 200k CU. Fix: Use
dynamicComputeUnitLimit: true. - Mainnet-only pools - Devnet has thin liquidity. Fix: Test routing on mainnet fork via Surfpool 0.12.0, not bare devnet.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Direct AMM CPI | You control pool + want minimal deps | You need best price across venues |
| Jupiter swap-instructions | Custom tx with your own ALTs | You want fastest path to a working swap |
| On-chain Jupiter program CPI | Swap inside your Anchor program | You need off-chain route discovery only |
FAQs
What slippage should I default to?
Start at 50 bps (0.5%) for liquid pairs. Raise to 100-300 bps for thin pools or volatile launches.
Can I swap inside an on-chain program?
Yes - CPI into Jupiter's on-chain program with accounts from swap-instructions. Off-chain routing still discovers the path.
How do I handle priority fees?
Pass prioritizationFeeLamports: "auto" in the swap request, or set an explicit lamport value from your fee oracle.
Does Jupiter support exact-out swaps?
Use swapMode=ExactOut on the quote endpoint when you need a precise output amount (e.g., repay exact debt).
Why did my swap simulate OK but fail on-chain?
Quote staleness, account lock contention, or priority fee too low. Re-quote and bump CU/priority fee.
Can I restrict which DEXes Jupiter uses?
Yes - pass dexes allow/deny lists on the quote API to exclude untrusted venues.
How do I log the route for debugging?
Inspect quote.routePlan - each step shows swapInfo with AMM label, in/out amounts, and pool address.
Is the quote API rate-limited?
Heavy server traffic should cache quotes briefly and backoff on HTTP 429. Consider Jupiter paid tiers for production.
How do I test without mainnet SOL?
Use Surfpool 0.12.0 mainnet fork with funded test wallets, or devnet with known pool mints (limited routes).
What token program does Jupiter expect?
Token-2022 mints are supported on many routes but not all pools. Check routePlan token program IDs per leg.
Related
- DeFi Basics on Solana - composability overview
- AMMs (Raydium, Orca, Meteora) - venues Jupiter routes through
- Jito & MEV - landing swaps under contention
- DeFi Integrations Best Practices - production swap policy
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.