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:
- Finds the best route across supported DEXs
- Calculates fee from swap amount (not separate wallet balance)
- Creates all required accounts (ATAs if needed)
- Builds DEX swap instructions for the optimal pool
- Adds fee transfer instruction (direct token transfer, no temp accounts)
- 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
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
wallet | string | ✅ | User's wallet public key | |
amount | number | ✅ | Amount to swap (UI units, e.g., 0.1 SOL) | |
inputMint | string | ✅ | Input token mint address | |
outputMint | string | ✅ | Output token mint address | |
router | string | ❌ | "vybe" | Router mode: "vybe", "titan", "jupiter" |
slippage | number | ❌ | 5 | Slippage tolerance (percentage, e.g., 2 for 2%) |
fee | number | ❌ | 0 | Service fee percentage (e.g., 1 for 1%) |
simulate | boolean | ❌ | false | Simulate only, don't return transaction |
gasless | boolean | ❌ | false | Use Vybe as fee payer |
protocol | string | ❌ | Force specific protocol (e.g., "PUMPFUN") | |
pool | string | ❌ | Force specific pool address | |
vybeOnly | boolean | ❌ | false | No 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
| Field | Description |
|---|---|
transaction | Base64-encoded unsigned transaction |
inputAmount | Input amount in base units |
inputToken | Input token mint address |
outputToken | Output token mint address |
inputDecimals | Input token decimal places |
outputDecimals | Output token decimal places |
swapFee | Fee amount in base units |
protocol | DEX protocol used |
poolAddress | Pool address used for swap |
quote | Quote 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
| Router | Behavior | Use When |
|---|---|---|
"vybe" | Direct DEX calls, falls back to Titan/Jupiter if needed | Maximum efficiency |
"titan" | Uses Titan aggregator | Wide token coverage |
"jupiter" | Uses Jupiter aggregator | Maximum 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
| Status | Error | Cause | Solution |
|---|---|---|---|
| 400 | Missing required parameters | Required fields not provided | Include all required fields |
| 400 | Invalid wallet format | Wallet is not a valid public key | Check wallet address |
| 422 | No swap route found | No liquidity for this pair | Try different router or check token |
| 422 | Insufficient balance | Wallet doesn't have enough tokens | Check balance before swap |
| 422 | Slippage exceeded | Price moved too much | Increase 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
- Supported Protocols - Force specific DEXs
- Slippage & Fees - Configure slippage and understand fees
- Gasless Mode - Execute without SOL for gas
Updated 4 days ago