Build Transaction

Build an unsigned swap transaction ready for signing and submission. The API returns a base64-encoded transaction containing all necessary instructions—token transfers, DEX calls, and fee handling—in a single atomic transaction.

How It Works

The build transaction endpoint:

  1. Finds the best route across supported DEXs
  2. Calculates fee from swap amount (not separate wallet balance)
  3. Creates all required accounts (ATAs if needed)
  4. Builds DEX swap instructions for the optimal pool
  5. Adds fee transfer instruction (direct token transfer, no temp accounts)
  6. Returns a base64 transaction ready for signing

You receive a complete, optimized transaction that just needs a signature.

Note: Your application signs the transaction with the user's wallet and submits it to the Solana network. Vybe never touches private keys—we only build the transaction; signing and submission happen entirely on your side


Smart Fee Handling

When you set a fee, Vybe deducts it from the swap tokens directly—not from a separate wallet balance. This means:

  • No "Insufficient SOL for fee" errors when swapping SOL
  • No temporary fee accounts (saves at least ~0.004 SOL in rent)
  • Fee is extracted atomically within the same transaction

See Slippage & Fees for full details on fee priority logic.


Endpoint

POST /trading/swap

Request Parameters

ParameterTypeRequiredDefaultDescription
walletstringUser's wallet public key
amountnumberAmount to swap (UI units, e.g., 0.1 SOL)
inputMintstringInput token mint address
outputMintstringOutput token mint address
routerstring"vybe"Router mode: "vybe", "titan", "jupiter"
slippagenumber5Slippage tolerance (percentage, e.g., 2 for 2%)
feenumber0Service fee percentage (e.g., 1 for 1%)
simulatebooleanfalseSimulate only, don't return transaction
gaslessbooleanfalseUse Vybe as fee payer
protocolstringForce specific protocol (e.g., "PUMPFUN")
poolstringForce specific pool address
vybeOnlybooleanfalseNo fallback to aggregators

Example Request

curl -X POST "https://api.vybenetwork.com/trading/swap" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "wallet": "7Tar8QZTrRPwoGY5Ke9Vfwf6CmpBfekrNofERxgReza",
    "amount": 0.1,
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "router": "vybe",
    "slippage": 1,
    "fee": 0.5
  }'

Example Response

{
  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHDg...",
  "inputAmount": 100000000,
  "inputToken": "So11111111111111111111111111111111111111112",
  "outputToken": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "inputDecimals": 9,
  "outputDecimals": 6,
  "swapFee": 500000,
  "protocol": "RAYDIUM_CLMM",
  "poolAddress": "8sLbNZoA1cfnvMJLPfp98ZLAnFSYCFApfJKMbiXNLwxj",
  "quote": {
    "inAmount": "100000000",
    "outAmount": "18523456",
    "priceImpactPct": 0.01
  }
}

Response Fields

FieldDescription
transactionBase64-encoded unsigned transaction
inputAmountInput amount in base units
inputTokenInput token mint address
outputTokenOutput token mint address
inputDecimalsInput token decimal places
outputDecimalsOutput token decimal places
swapFeeFee amount in base units
protocolDEX protocol used
poolAddressPool address used for swap
quoteQuote details (amounts, price impact)

Complete Flow: Sign and Submit

Here's how to execute a swap end-to-end:

Using @solana/web3.js

import { Connection, Transaction, Keypair } from '@solana/web3.js';

async function executeSwap(wallet, inputMint, outputMint, amount) {
  // Step 1: Build the transaction
  const response = await fetch('https://api.vybenetwork.com/trading/swap', {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      wallet: wallet.publicKey.toString(),
      amount,
      inputMint,
      outputMint,
      router: 'vybe',
      slippage: 2
    })
  });
  
  const { transaction: txBase64, quote } = await response.json();
  
  // Step 2: Deserialize the transaction
  const transaction = Transaction.from(Buffer.from(txBase64, 'base64'));
  
  // Step 3: Sign with wallet
  transaction.sign(wallet);
  
  // Step 4: Submit to network
  const connection = new Connection('https://api.mainnet-beta.solana.com');
  const signature = await connection.sendRawTransaction(
    transaction.serialize(),
    { skipPreflight: false }
  );
  
  // Step 5: Confirm
  await connection.confirmTransaction(signature, 'confirmed');
  
  return {
    signature,
    expectedOutput: quote.outAmount
  };
}

Using Wallet Adapter (React)

import { useWallet, useConnection } from '@solana/wallet-adapter-react';
import { Transaction } from '@solana/web3.js';

function SwapButton({ inputMint, outputMint, amount }) {
  const { publicKey, signTransaction } = useWallet();
  const { connection } = useConnection();
  const [loading, setLoading] = useState(false);
  
  async function handleSwap() {
    if (!publicKey || !signTransaction) return;
    
    setLoading(true);
    try {
      // Build transaction
      const response = await fetch('https://api.vybenetwork.com/trading/swap', {
        method: 'POST',
        headers: {
          'X-API-Key': API_KEY,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          wallet: publicKey.toString(),
          amount,
          inputMint,
          outputMint,
          router: 'vybe',
          slippage: 2
        })
      });
      
      const { transaction: txBase64 } = await response.json();
      
      // Deserialize
      const transaction = Transaction.from(Buffer.from(txBase64, 'base64'));
      
      // Sign with wallet adapter
      const signed = await signTransaction(transaction);
      
      // Submit
      const signature = await connection.sendRawTransaction(signed.serialize());
      await connection.confirmTransaction(signature, 'confirmed');
      
      console.log('Swap successful:', signature);
    } catch (error) {
      console.error('Swap failed:', error);
    }
    setLoading(false);
  }
  
  return (
    <button onClick={handleSwap} disabled={loading}>
      {loading ? 'Swapping...' : 'Swap'}
    </button>
  );
}

Router Options

RouterBehaviorUse When
"vybe"Direct DEX calls, falls back to Titan/Jupiter if neededMaximum efficiency
"titan"Uses Titan aggregatorWide token coverage
"jupiter"Uses Jupiter aggregatorMaximum coverage

Force Direct Integration Only

{
  "router": "vybe",
  "vybeOnly": true
}

This prevents any fallback to aggregators. If Vybe Router doesn't support the token pair, the request will fail.


Simulation Mode

Test swaps without creating a transaction:

{
  "wallet": "...",
  "amount": 1,
  "inputMint": "...",
  "outputMint": "...",
  "simulate": true
}

Returns quote and route information without the transaction, useful for testing and price discovery.


Error Handling

StatusErrorCauseSolution
400Missing required parametersRequired fields not providedInclude all required fields
400Invalid wallet formatWallet is not a valid public keyCheck wallet address
422No swap route foundNo liquidity for this pairTry different router or check token
422Insufficient balanceWallet doesn't have enough tokensCheck balance before swap
422Slippage exceededPrice moved too muchIncrease slippage tolerance

Robust Error Handling

async function buildSwapWithRetry(params, maxRetries = 2) {
  for (let i = 0; i <= maxRetries; i++) {
    try {
      const response = await fetch('https://api.vybenetwork.com/trading/swap', {
        method: 'POST',
        headers: {
          'X-API-Key': API_KEY,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(params)
      });
      
      if (!response.ok) {
        const error = await response.json();
        
        // Retry with higher slippage on slippage errors
        if (error.message?.includes('Slippage') && i < maxRetries) {
          params.slippage = (params.slippage || 2) * 2;
          continue;
        }
        
        throw new Error(error.message || 'Swap failed');
      }
      
      return response.json();
    } catch (error) {
      if (i === maxRetries) throw error;
    }
  }
}

Next Steps