Skip to main content
Single endpoint, same shape as EVM / TON. The Solana-specific calldata sits under data.solana. See the Swap Quoting page for the full input parameters.

SOL addresses in swap requests

So11111111111111111111111111111111111111111
Use So11111111111111111111111111111111111111111 when the user holds native SOL in their wallet and wants to swap from or receive native SOL. Wrapped SOL is a real SPL mint and uses So11111111111111111111111111111111111111112. Use the wrapped SOL mint only when the user is explicitly swapping WSOL token-account balance, not their native lamports balance.

Request

GET /api/2/swap/quoting?chainId=solana:solana
  &tokenIn=So11111111111111111111111111111111111111111
  &tokenOut=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
  &amount=1
  &walletAddress=8ZmF…
  &slippage=auto
  &prioritizationFeeLamports=auto
  &computeUnitLimit=true
  &jitoTipLamports=10000
  &feePercentage=0.5
  &feeWallet=8ZmF…
ParamRequiredNotes
chainIdsolana:solana
tokenIn / tokenOutToken address. Native SOL sentinel = So11111111111111111111111111111111111111111. Wrapped SOL SPL mint = So11111111111111111111111111111111111111112.
amount or amountRawHuman-readable ("1.5") or raw ("1500000" for 6-decimal USDC)
walletAddressUser’s Solana base58 pubkey. It signs/funds the swap and receives tokenOut unless destinationWallet or finalRecipientWallet is provided.
slippageauto or fixed percentage 0-100. Default: auto.
prioritizationFeeLamportsJupiter-compatible priority fee budget: auto, fixed lamports, or {"priorityLevelWithMaxLamports":{"priorityLevel":"medium" | "high" | "veryHigh","maxLamports":1000000,"global":false}}
computeUnitLimittrue by default; dynamically sizes the Solana compute limit from the built swap instructions. You can also pass a fixed integer.
jitoTipLamportsAdd a Jito tip transfer to one of the official tip accounts
multiLandertrue returns N candidates over a durable nonce — see Multi-lander
landerTipLamportsPer-lander tip when multiLander=true
payerAddressFee abstraction — separate fee payer from walletAddress
destinationWalletSends output to another wallet when supported. Mutually exclusive with finalRecipientWallet.
finalRecipientWalletRouter-enforced final output recipient. The router sends the exact post-swap output to this wallet after swap, fees, and slippage checks. Mutually exclusive with destinationWallet.
feePercentageCaller referral fee 0-99% (taken from input or output SOL)
feeWalletRequired when feePercentage > 0 (and for minFeesNative / feeToken)
minFeesNativeMinimum referral fee in SOL, e.g. 0.05. Floors the referral fee — max(amountIn × feePercentage/100, minFeesNative) — enforced on-chain by MobulaRouter when the fee asset is native SOL.
feeTokenMint of a token to charge a flat minimum fee in (with minFeesTokenRaw). Transferred to feeWallet via a dedicated instruction, independent of the route.
minFeesTokenRawRaw amount (smallest unit) of feeToken to charge. Tx reverts if the user’s balance is insufficient.
onlyRoutersComma-list of jupiter,naos,kyberswap,lifi
excludedProtocols / onlyProtocolsDEX-level filter (e.g. raydium,orca,pump-amm)

Recipient controls

By default, walletAddress receives the output token. Use destinationWallet for a simple recipient override when supported by the route. Use finalRecipientWallet when the Mobula Solana router must transfer the exact final output amount after swap execution, fees, and slippage checks. destinationWallet and finalRecipientWallet are mutually exclusive. payerAddress only changes the Solana fee payer/signing wallet; it does not redirect the swap output.

Response — data.solana

{
  "data": {
    "amountOutTokens": "245.123",
    "amountInUSD": 200.45,
    "amountOutUSD": 199.87,
    "slippagePercentage": 3.5,
    "marketImpactPercentage": 0.04,
    "poolFeesPercentage": 0.25,
    "tokenIn":  { "address": "So11111111111111111111111111111111111111111", "symbol": "SOL",  "decimals": 9 },
    "tokenOut": { "address": "EPjF…",     "symbol": "USDC", "decimals": 6 },
    "requestId": "f8b2…",
    "details": {
      "route": {
        "hops": [
          {
            "poolAddress": "5Q5…",
            "exchange": "Raydium",
            "poolType": "CLMM",
            "amountInRaw": "1000000000",
            "amountOutRaw": "245100000",
            "feePercentage": 0.25,
            "feeBps": 25,
            "feeSource": "pool",
            "marketImpactPercentage": 0.04,
            "priceImpactPercentage": 0.04,
            "volume24hUSD": 1234567.89,
            "ranking": 1
          }
        ],
        "totalFeePercentage": 0.25,
        "aggregator": "jupiter"
      }
    },
    "fee": { "amount": "0.001", "percentage": 0.5, "wallet": "8ZmF…", "deductedFrom": "input" },
    "solana": {
      "transaction": {
        "serialized": "base64-encoded-VersionedTransaction-bytes",
        "variant": "versioned"
      },
      "lastValidBlockHeight": 269450123
    },
    "evm": null,
    "ton": null
  }
}

data.solana fields

FieldTypeDescription
transaction.serializedbase64Full Solana transaction. Deserialize with VersionedTransaction.deserialize (or Transaction.from for legacy).
transaction.variant'versioned' | 'legacy'Discriminator — almost always 'versioned' in practice.
lastValidBlockHeightnumberBlockhash expiry — your client should broadcast before the chain ticks past this.

Multi-lander

Set multiLander=true to receive N candidate transactions sharing a durable nonce. Race them across Jito / Nozomi / 0slot for fastest landing — only one can commit.
{
  "data": {
    "candidates": [
      { "lander": "jito",     "serialized": "base64…", "tipAccount": "Cw8C…", "tipLamports": 1000 },
      { "lander": "nozomi",   "serialized": "base64…", "tipAccount": "TpdX…", "tipLamports": 1000 },
      { "lander": "zeroslot", "serialized": "base64…", "tipAccount": "6fQa…", "tipLamports": 1000 }
    ],
    "nonceAccount": "Hgs…",
    "nonceAuthority": "BvW…",
    "solana": null,
    "evm": null,
    "ton": null
  }
}
Sign every candidate, POST them all to /swap/send in batch mode (candidates: [{lander, signedTransaction}, …]).

Signing

import { VersionedTransaction } from '@solana/web3.js';

const tx = VersionedTransaction.deserialize(
  Buffer.from(quote.data.solana.transaction.serialized, 'base64'),
);
// Sign via wallet (Phantom / Privy / Backpack / etc.).
const signed = await wallet.signTransaction(tx);
const signedBase64 = Buffer.from(signed.serialize()).toString('base64');

await fetch('/api/2/swap/send', {
  method: 'POST',
  body: JSON.stringify({ chainId: 'solana:solana', signedTransaction: signedBase64 }),
});

Supported aggregators

Jupiter, KyberSwap, NAOS, Li.Fi — pick one or several via onlyRouters. Per-DEX filtering (Raydium, Orca, Meteora DLMM/Damm, Pump AMM, Whirlpool, …) via onlyProtocols / excludedProtocols.

Limits

  • Blockhash expirylastValidBlockHeight is ~150 slots (60s). Re-quote if the user takes longer than that to sign.
  • Priority budget — use prioritizationFeeLamports with computeUnitLimit=true so the CU price is derived from the final compute limit. When bundling with Jito, set jitoTipLamports separately.
  • Address forms — Solana addresses are case-sensitive base58. Don’t lowercase.