Jupiter Aggregator Solana API: The Complete Developer Guide
Master Jupiter Aggregator's Solana API to fetch swap quotes, execute trades, and build automated trading bots with real Python and JavaScript code examples.
Master Jupiter Aggregator's Solana API to fetch swap quotes, execute trades, and build automated trading bots with real Python and JavaScript code examples.
Jupiter has quietly become the backbone of Solana DeFi. Nearly every swap that happens on the chain — whether from a wallet UI, a trading bot, or a mobile app — routes through Jupiter's aggregation engine. The reason is simple: Jupiter finds the best price across every major Solana DEX simultaneously, splitting orders across Orca, Raydium, Meteora, and others in a single atomic transaction. If you're building anything that touches Solana trading, you need to understand its API. This guide walks you through the full stack — from your first quote request to production-grade swap execution with error handling.
Before touching the API, it helps to understand what's happening under the hood. When you send a quote request, Jupiter's routing engine searches across all integrated liquidity sources — AMMs, order books, concentrated liquidity pools — and computes the optimal split to minimize slippage and maximize output. This is called smart order routing, and it's why swapping through Jupiter typically beats going directly to any single DEX. The engine handles single-hop swaps (SOL → USDC) and multi-hop routes (SOL → BONK → JUP → USDC) transparently. You just specify input and output tokens; Jupiter figures out the path.
Jupiter's public API requires no API key and has no authentication. Rate limits apply at roughly 10 requests/second for the public tier. For production bots with higher throughput, use a dedicated RPC and consider Jupiter's paid tier or self-hosted routing.
The Jupiter API is plain HTTP — you can hit it with curl, Postman, Python's requests library, or JavaScript's fetch. No special SDK is required for reading quotes and prices. For actually executing swaps, you'll need a Solana wallet library to sign transactions. Here's the minimal Python setup to get started:
# Install dependencies
# pip install requests solders base58
import requests
import base64
from solders.keypair import Keypair
from solders.transaction import VersionedTransaction
# Token mint addresses (copy these exactly)
SOL_MINT = "So11111111111111111111111111111111111111112"
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
BONK_MINT = "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"
JUP_MINT = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"
# Jupiter API base URLs
QUOTE_API = "https://quote-api.jup.ag/v6/quote"
SWAP_API = "https://quote-api.jup.ag/v6/swap"
PRICE_API = "https://price.jup.ag/v6/price"
print("Jupiter API environment ready")
The quote endpoint is your workhorse. You send it an input token, output token, and the amount (in the token's smallest unit — lamports for SOL, which has 9 decimals; base units for USDC, which has 6). It returns a full routing plan including expected output, price impact, and the exact route taken. This is read-only and free to call — perfect for price feeds, dashboards, and pre-trade analysis.
def get_jupiter_quote(
input_mint: str,
output_mint: str,
amount: int,
slippage_bps: int = 50
) -> dict:
"""
Fetch a swap quote from Jupiter.
amount: in smallest token units (lamports for SOL)
slippage_bps: slippage tolerance in basis points (50 = 0.5%)
"""
params = {
"inputMint": input_mint,
"outputMint": output_mint,
"amount": amount,
"slippageBps": slippage_bps,
"onlyDirectRoutes": False, # Allow multi-hop for better price
"asLegacyTransaction": False # Use versioned transactions
}
response = requests.get(QUOTE_API, params=params, timeout=10)
response.raise_for_status()
return response.json()
# Example: get price of 1 SOL in USDC
# 1 SOL = 1_000_000_000 lamports
quote = get_jupiter_quote(SOL_MINT, USDC_MINT, 1_000_000_000)
out_amount = int(quote["outAmount"]) / 1_000_000 # USDC has 6 decimals
price_impact = float(quote["priceImpactPct"])
route_label = " -> ".join(
leg["swapInfo"]["label"] for leg in quote["routePlan"]
)
print(f"1 SOL = {out_amount:.4f} USDC")
print(f"Price impact: {price_impact:.4f}%")
print(f"Route: {route_label}")
# Output example:
# 1 SOL = 148.3201 USDC
# Price impact: 0.0001%
# Route: Orca -> Raydium
| Field | Type | Description |
|---|---|---|
| outAmount | string | Expected output in smallest token units |
| otherAmountThreshold | string | Minimum output after slippage applied |
| priceImpactPct | string | Price impact percentage for this trade size |
| routePlan | array | Ordered list of DEX hops with pool details |
| contextSlot | number | Solana slot at which quote was computed |
| timeTaken | number | Routing computation time in seconds |
Fetching a quote is one thing — actually sending the transaction is where it gets interesting. Jupiter's swap endpoint takes your quote response and builds a serialized, ready-to-sign Solana transaction. You deserialize it, sign with your wallet, and broadcast to the network. The whole round trip from quote to confirmed transaction typically takes 2-5 seconds on a good RPC. Unlike placing an order on Binance or Bybit where you interact with a centralized order book, here you own the private key and the transaction is non-custodial — the funds never leave your wallet until the swap settles atomically on-chain.
import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js";
import fetch from "cross-fetch";
import bs58 from "bs58";
const RPC_URL = "https://api.mainnet-beta.solana.com";
const connection = new Connection(RPC_URL, "confirmed");
async function executeJupiterSwap(wallet, quoteResponse) {
// Step 1: Build the swap transaction
const swapRes = await fetch("https://quote-api.jup.ag/v6/swap", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
quoteResponse,
userPublicKey: wallet.publicKey.toString(),
wrapAndUnwrapSol: true, // Auto-wrap SOL <-> wSOL
prioritizationFeeLamports: 5000 // Priority fee to land faster
})
});
if (!swapRes.ok) {
throw new Error(`Swap build failed: ${await swapRes.text()}`);
}
const { swapTransaction } = await swapRes.json();
// Step 2: Deserialize, sign, and send
const txnBytes = Buffer.from(swapTransaction, "base64");
const txn = VersionedTransaction.deserialize(txnBytes);
txn.sign([wallet]);
const txid = await connection.sendRawTransaction(txn.serialize(), {
skipPreflight: false,
maxRetries: 3
});
console.log(`Swap submitted: https://solscan.io/tx/${txid}`);
// Step 3: Wait for confirmation
const confirmation = await connection.confirmTransaction(txid, "confirmed");
if (confirmation.value.err) {
throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
}
console.log(`Confirmed in slot ${confirmation.context.slot}`);
return txid;
}
// Usage:
// const wallet = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY));
// const quote = await fetchQuote(...);
// const txid = await executeJupiterSwap(wallet, quote);
Never hardcode private keys. Use environment variables or encrypted key management. On production bots, consider using a dedicated hot wallet with only the minimum balance needed — never your main wallet.
A quote that worked 3 seconds ago may be stale by the time you broadcast. Slippage, RPC timeouts, and network congestion are real problems in production. Your bot needs to handle all of them gracefully. The pattern below covers retry logic with exponential backoff, quote expiry validation, and distinguishes between retryable network errors and hard failures like insufficient balance or route not found. Platforms like OKX and Binance have WebSocket APIs that feed you real-time prices to decide when to trigger swaps — combining their price feeds with VoiceOfChain trading signals and Jupiter execution gives you a complete automated pipeline.
import requests
import time
from typing import Optional
def get_quote_with_retry(
input_mint: str,
output_mint: str,
amount: int,
slippage_bps: int = 50,
max_retries: int = 3
) -> Optional[dict]:
url = "https://quote-api.jup.ag/v6/quote"
params = {
"inputMint": input_mint,
"outputMint": output_mint,
"amount": amount,
"slippageBps": slippage_bps
}
for attempt in range(max_retries):
try:
resp = requests.get(url, params=params, timeout=8)
# 400 = bad params (wrong mint, amount too small) — don't retry
if resp.status_code == 400:
error_msg = resp.json().get("error", "Unknown error")
print(f"[Jupiter] Bad request: {error_msg}")
return None
# 429 = rate limited — back off and retry
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 2))
print(f"[Jupiter] Rate limited, waiting {retry_after}s")
time.sleep(retry_after)
continue
resp.raise_for_status()
quote = resp.json()
# Warn on high price impact (>1% is significant)
impact = float(quote.get("priceImpactPct", 0))
if impact > 0.01:
print(f"[Jupiter] WARNING: {impact:.2%} price impact")
return quote
except requests.exceptions.Timeout:
print(f"[Jupiter] Timeout on attempt {attempt + 1}/{max_retries}")
except requests.exceptions.ConnectionError as e:
print(f"[Jupiter] Connection error: {e}")
# Exponential backoff: 1s, 2s, 4s
if attempt < max_retries - 1:
sleep_time = 2 ** attempt
print(f"[Jupiter] Retrying in {sleep_time}s...")
time.sleep(sleep_time)
print("[Jupiter] All retries exhausted")
return None
# Price impact thresholds for different trade sizes
SIZE_THRESHOLDS = {
"small": {"max_usd": 1_000, "max_impact_bps": 10}, # <$1k: <0.1%
"medium": {"max_usd": 50_000, "max_impact_bps": 30}, # <$50k: <0.3%
"large": {"max_usd": 500_000, "max_impact_bps": 100}, # <$500k: <1%
}
def is_quote_acceptable(quote: dict, trade_usd: float) -> bool:
"""Return False if price impact is too high for this trade size."""
impact_bps = float(quote["priceImpactPct"]) * 10_000
for tier in SIZE_THRESHOLDS.values():
if trade_usd <= tier["max_usd"]:
return impact_bps <= tier["max_impact_bps"]
return impact_bps <= 200 # >$500k: hard cap at 2%
Integrating signal feeds is where this becomes a real trading system. VoiceOfChain publishes real-time signals for Solana-native tokens — when a buy signal fires for a token like JUP or BONK, your bot can immediately query Jupiter for a quote, validate the price impact against your thresholds, and execute the swap within seconds. Compare that to the latency of manually checking prices on Bybit or Gate.io and placing an order: the API-driven approach cuts reaction time from minutes to under 5 seconds.
Jupiter's API gives developers direct access to the deepest liquidity pool on Solana without managing connections to dozens of individual DEXes. The quote-to-swap workflow is straightforward: fetch a quote with your parameters, validate price impact and slippage, build the transaction via the swap endpoint, sign locally, and broadcast. The code patterns in this guide — retry logic, impact thresholds, atomic transaction signing — are the foundation of any serious Solana trading system. Layer in real-time signal feeds from platforms like VoiceOfChain, combine with price alerts from Binance or OKX for cross-market context, and you have the ingredients for a fully automated on-chain trading operation running around the clock.