If you're building anything on Solana that does swaps — wallets, trading bots, DeFi UIs, dApps with token-to-token flows — you'll usually end up integrating Jupiter's swap API. It's the de-facto aggregator for Solana, it's well-engineered, and the routing it produces is generally hard to beat with custom logic.
But "use Jupiter" isn't the whole answer. The integration has nuances, the swap quality depends as much on your RPC stack as on Jupiter itself, and there are common mistakes that turn a clean integration into a slow or expensive one.
This piece covers what Jupiter does (and doesn't do), how to integrate the swap API correctly, and the architectural decisions that affect your fill quality.
What Jupiter Actually Does
Jupiter is a swap aggregator. You ask it "swap X SOL for as much TOKEN as possible." It searches across many DEXes and routing paths, finds the best path, and gives you back a transaction you can sign and submit.
The whole package — quote endpoint, swap endpoint, routing engine — is what people generally mean by the jupiter aggregator api. The current generation is Jupiter v6, which is what we'll use throughout this article. The pieces:
- Quote API. Given a swap pair and amount, return the best route with expected output.
- Swap API. Given a quote, return a serialised transaction ready to sign.
- Versioned transactions / ALTs. Most Jupiter routes use versioned transactions with address lookup tables, which lets them include more accounts than legacy transactions allow.
If you've also looked at Raydium swap API or routing directly through specific raydium liquidity pool v4 / raydium authority v4 state, that's the lower-level alternative — it skips the aggregator and trades directly against one DEX. Faster for simple paths, but you give up Jupiter's multi-hop routing across the whole ecosystem.
Jupiter handles the routing, the transaction construction, the slippage tolerance setup. What it doesn't handle: the quality of your transaction submission to the network. That's still on you.
The Basic Integration Pattern
const QUOTE_URL = "https://quote-api.jup.ag/v6/quote";
const SWAP_URL = "https://quote-api.jup.ag/v6/swap";
// Step 1: get a quote
const quoteResp = await fetch(`${QUOTE_URL}?` + new URLSearchParams({
inputMint: SOL_MINT,
outputMint: TARGET_TOKEN_MINT,
amount: String(lamports),
slippageBps: "100", // 1% slippage tolerance
}));
const quote = await quoteResp.json();
// Step 2: build the swap transaction
const swapResp = await fetch(SWAP_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
quoteResponse: quote,
userPublicKey: wallet.publicKey.toString(),
wrapAndUnwrapSol: true,
dynamicComputeUnitLimit: true,
}),
});
const { swapTransaction } = await swapResp.json();
// Step 3: deserialise, sign, submit
const txBuf = Buffer.from(swapTransaction, "base64");
const tx = VersionedTransaction.deserialize(txBuf);
tx.sign([wallet]);
const signature = await connection.sendTransaction(tx, {
skipPreflight: true,
maxRetries: 0,
});
This is the minimum viable integration. The next sections cover what to think about beyond it.
Slippage: The Single Biggest Decision
Slippage tolerance (slippageBps) is the parameter that decides whether your swaps land or fail. Too tight and a price move during execution causes the transaction to fail. Too loose and you eat unnecessary slippage on every trade.
Considerations:
- Pool depth matters more than token volatility. A shallow pool with a stable-looking token still moves a lot per swap. Set slippage based on actual pool impact.
- Volatility during congestion is higher. Routes you set up during peak hours need more tolerance than off-peak.
- Multi-hop routes compound slippage. A 3-hop route doesn't have the same slippage profile as 3x a 1-hop route.
A reasonable approach: estimate slippage based on the route's pool depths and price impact, then add a buffer for execution latency. Don't use a single fixed number across all swaps.
RPC Choice Matters More Than You Think
Jupiter constructs the transaction; you submit it. The RPC you submit through decides:
- How fast the transaction lands. Jupiter's good routing is wasted if your transaction lands 5 slots later than competitors'.
- Whether you get sandwiched. Every Jupiter swap is a potential sandwich target. Without Anti-MEV routing, you're paying tax on every swap regardless of how good Jupiter's routing was.
- What happens during congestion. When network is busy, the RPC determines whether your transaction makes it in.
The pattern: Jupiter for routing, an Anti-MEV write-optimised RPC for submission.
Common Integration Mistakes
Things we've seen developers do that create production issues:
Using sendRawTransaction without setting skipPreflight. The default behaviour wastes a round-trip simulating against a transaction Jupiter already validated.
Forgetting dynamicComputeUnitLimit: true. Without this, the transaction may have insufficient CU budget for the route. Always set it.
Not refreshing the quote before submitting. A quote from 30 seconds ago has stale prices. For latency-sensitive use, fetch the quote, build, sign, and submit within a tight window.
Same blockhash across retries. Jupiter gives you a transaction with a specific blockhash. If you retry, build a fresh transaction with a fresh blockhash.
Submitting the same transaction to multiple RPCs. Sounds like redundancy; creates duplicates and complications. Pick one RPC for sends.
Not handling Jupiter API rate limits. Heavy quote traffic gets rate-limited. Cache quotes for non-time-sensitive use; back off on rate limit responses.
Hardcoding the Jupiter URL. Like RPC URLs, Jupiter has different environments. Use environment variables.
Specific Tips for Trading Bots
If you're using Jupiter from a bot:
Cache quotes selectively. For a bot probing many tokens for opportunities, you can cache quote responses for a few hundred ms. For a bot with a specific position decision, fetch fresh.
Pre-build transactions when possible. If you know you're going to swap from SOL to TOKEN_X soon, fetch the quote and build the transaction in advance, then sign and submit when the trigger fires.
Use dynamicSlippage: true. Jupiter's API supports this; lets the system pick a slippage tolerance based on route characteristics. Often better than your fixed number.
Tip explicitly. Jupiter doesn't handle priority fees for you. Add a ComputeBudgetProgram.setComputeUnitPrice instruction or use a wrapper that does.
Match RPC to workload. Jupiter for routing, an Anti-MEV RPC for sending. Read traffic on a different provider if cost matters.
When You Shouldn't Use Jupiter
Jupiter is the right choice for most swap use cases. A few exceptions:
You have a specific theory about routes Jupiter is missing. Some niche pairs benefit from custom routing. Build your own only if you've verified Jupiter is missing a real opportunity.
You're integrating directly with a single DEX for performance. If you're only ever swapping on one specific Raydium pool, going direct can be faster than Jupiter's routing layer.
You need full control over transaction structure. Some advanced patterns (atomic multi-swap with custom logic, integration with non-DEX programs in the same transaction) need direct construction.
You're high-frequency at the slot level. Jupiter's API has its own latency. For sub-100ms reactivity, sometimes you need direct construction.
For 95% of use cases, Jupiter is the answer.
What to Do This Week
If you're integrating Jupiter:
- Set up Jupiter quote + swap with the basic pattern. Get something working end-to-end.
- Test your slippage tolerance against real pool depths. Don't use a static value across all routes.
- Pair Jupiter with an Anti-MEV write RPC. Don't waste Jupiter's good routing on a submission path that gets sandwiched.
- Add per-signature telemetry. Track which swaps land, what slippage was set, what the actual fill was vs expected.
- Profile the latency from quote → submit → land. If it's high, the bottleneck is usually the RPC.
- Set
dynamicComputeUnitLimit: trueanddynamicSlippage: trueas defaults.
Try BoltTx for Jupiter Integration
BoltTx complements Jupiter for the submission side:
import { Connection, VersionedTransaction } from "@solana/web3.js";
const connection = new Connection(
"https://bolttx.io/?api-key=YOUR_API_KEY",
"processed"
);
// ... build transaction with Jupiter ...
const signature = await connection.sendTransaction(tx, {
skipPreflight: true,
maxRetries: 0,
});
BoltTx handles the submission path: sub-second confirmation, native Anti-MEV routing, SWQoS-aware delivery. Jupiter handles the routing. The combination is what most production Solana applications running serious volume actually use.
Free tier signup. Run real Jupiter swaps through it for a week and compare your effective fills to your current setup. The difference is what Jupiter alone can't fix.
FAQ
Is the Jupiter Swap API free? Yes, the API itself is free. You pay swap fees on the actual transactions, plus your priority fees and tips.
Can I use Jupiter without an aggregator account? Yes, no account needed for basic usage. Some advanced features and rate limit increases need API keys.
Does Jupiter handle slippage protection automatically? Jupiter sets the minimum output based on your slippage tolerance. If the actual output would be less than that minimum, the transaction reverts.
What's dynamicComputeUnitLimit for?
Tells Jupiter to set the compute unit budget based on the actual route. Without it, the budget may be too low for complex routes.
Should I use Jupiter v4 or v6? v6 is current and has improvements over v4. Use v6 unless you have specific reasons.
Why do my Jupiter swaps still get sandwiched? Because Jupiter constructs the transaction but you submit it. If your submission path is observable to MEV bots, you're a sandwich target regardless of how good Jupiter's routing is. The fix is at the RPC layer, not at Jupiter.
What's a Jupiter liquidity pool, and how does it relate to routing? Jupiter doesn't host its own pools — it routes through the jupiter liquidity pool set, which is the combined set of pools across every integrated DEX (Raydium, Orca, Meteora, Lifinity, Phoenix, etc.). When Jupiter "finds the best route," it's searching that combined liquidity graph. So jupiter liquidity pool in casual usage really means "all the pools Jupiter can route through."
I sometimes see "swa jupiter" as a search — typo or product? Just a typo for swap jupiter. Same product, same article, same answer.
Where do I find the raydium program id or the pumpfun program id? Both are fixed addresses published by their respective teams; you only look them up once and bake them into your bot's config. The raydium program id (and the v4 AMM authority) is documented on Raydium's GitHub; the pumpfun program id is on pump.fun's docs / on-chain. Bots interact with these programs by encoding instruction data against the published IDLs.