Skip to main content

Build Swap Transaction

The Swap API is one of the ways for you to interact with the Jupiter Swap Aggregator program. Before you send a transaction to the network, you will need to build the transaction that defines the instructions to execute and accounts to read/write to.

It can be complex to handle this yourself, but good news! Most of our APIs and SDKs just handles it for you, so you get a response with the transaction to be prepared and sent to the network.

Use Swap API to handle it for you or ...

If you are looking to interact with the Jupiter Swap Aggregator program in a different way, check out the other guides:

Swap Instructions

To compose with instructions and build your own transaction, read how to use the /swap-instructions in this section.

Flash Fill or Cross Program Invocation (CPI)

To interact with your own Solana program, read how to use the Flash Fill method or CPI in this section.

Let’s Get Started

In this guide, we will pick up from where Get Quote guide has left off.

If you have not set up your environment to use the necessary libraries, the RPC connection to the network and successfully get a quote from the Quote API, please start at get started or get quote.

API Reference

To fully utilize the Swap API, check out the Swap API Reference or Swap Instructions Reference.

Swap API

The root URL of the Swap API is as such.

https://api.jup.ag/swap/v1

From the previous guide on getting a quote, now using the quote response and your wallet, you can receive a serialized swap transaction that can be needs to be prepared and signed before sending to the network.

Get Serialized Transaction

Using the root URL and parameters to pass in, it is as simple as the example code below!

Optimizing for Transaction Landing is super super important!

This code block includes additional parameters that our Swap API supports, such as estimating compute units, priority fees and slippage, to optimize for transaction landing.

To understand how these parameters help, the next step, Send Swap Transaction guide will discuss them.

const swapResponse = await (
await fetch('https://api.jup.ag/swap/v1', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 'x-api-key': '' // enter api key here
},
body: JSON.stringify({
quoteResponse,
userPublicKey: wallet.publicKey.toString(),

// ADDITIONAL PARAMETERS TO OPTIMIZE FOR TRANSACTION LANDING
// See next guide to optimize for transaction landing
dynamicComputeUnitLimit: true,
dynamicSlippage: true,
prioritizationFeeLamports: {
priorityLevelWithMaxLamports: {
maxLamports: 1000000,
priorityLevel: "veryHigh"
}
}
})
})
).json();

console.log(swapResponse);

From the above example, you should see this response.

{
swapTransaction: 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAGDkS+3LuGTbs......+/oD9qb31dH6i0QZ2IHELXUX3Y1YeW79p9Stkqk12z4yvZFJiQ4GCQwLBwYQBgUEDggNTQ==',
lastValidBlockHeight: 279632475,
prioritizationFeeLamports: 9999,
computeUnitLimit: 388876,
prioritizationType: {
computeBudget: {
microLamports: 25715,
estimatedMicroLamports: 785154
}
},
dynamicSlippageReport: {
slippageBps: 50,
otherAmount: 20612318,
simulatedIncurredSlippageBps: -18,
amplificationRatio: '1.5',
categoryName: 'lst',
heuristicMaxSlippageBps: 100
},
simulationError: null
}

What’s Next

Now, you are able to get a quote and use our Swap API to build the swap transaction for you. Next steps is to proceed to prepare and sign the transaction and send the signed transaction to the network.

Let’s go sign and send!


Additional Resources

Build Your Own Transaction With Instructions

If you may prefer to compose with instructions instead of the provided transaction that is returned from the /swap endpoint (like the above example). You can post to /swap-instructions instead, it takes the same parameters as the /swap endpoint but returns you the instructions rather than the serialized transaction.

/swap-instructions code snippet
Example code snippet of using `/swap-instruction`
const instructions = await (
await fetch('https://api.jup.ag/swap-instructions/v1', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
quoteResponse,
userPublicKey: wallet.publicKey.toString(),
})
})
).json();

if (instructions.error) {
throw new Error("Failed to get swap instructions: " + instructions.error);
}

const {
tokenLedgerInstruction, // If you are using `useTokenLedger = true`.
computeBudgetInstructions, // The necessary instructions to setup the compute budget.
setupInstructions, // Setup missing ATA for the users.
swapInstruction: swapInstructionPayload, // The actual swap instruction.
cleanupInstruction, // Unwrap the SOL if `wrapAndUnwrapSol = true`.
addressLookupTableAddresses, // The lookup table addresses that you can use if you are using versioned transaction.
} = instructions;

const deserializeInstruction = (instruction) => {
return new TransactionInstruction({
programId: new PublicKey(instruction.programId),
keys: instruction.accounts.map((key) => ({
pubkey: new PublicKey(key.pubkey),
isSigner: key.isSigner,
isWritable: key.isWritable,
})),
data: Buffer.from(instruction.data, "base64"),
});
};

const getAddressLookupTableAccounts = async (
keys: string[]
): Promise<AddressLookupTableAccount[]> => {
const addressLookupTableAccountInfos =
await connection.getMultipleAccountsInfo(
keys.map((key) => new PublicKey(key))
);

return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => {
const addressLookupTableAddress = keys[index];
if (accountInfo) {
const addressLookupTableAccount = new AddressLookupTableAccount({
key: new PublicKey(addressLookupTableAddress),
state: AddressLookupTableAccount.deserialize(accountInfo.data),
});
acc.push(addressLookupTableAccount);
}

return acc;
}, new Array<AddressLookupTableAccount>());
};

const addressLookupTableAccounts: AddressLookupTableAccount[] = [];

addressLookupTableAccounts.push(
...(await getAddressLookupTableAccounts(addressLookupTableAddresses))
);

const blockhash = (await connection.getLatestBlockhash()).blockhash;
const messageV0 = new TransactionMessage({
payerKey: payerPublicKey,
recentBlockhash: blockhash,
instructions: [
// uncomment if needed: ...setupInstructions.map(deserializeInstruction),
deserializeInstruction(swapInstructionPayload),
// uncomment if needed: deserializeInstruction(cleanupInstruction),
],
}).compileToV0Message(addressLookupTableAccounts);
const transaction = new VersionedTransaction(messageV0);

Build Your Own Transaction With Flash Fill Or CPI

If you may prefer to interact with the Jupiter Swap Aggregator program with your own on-chain program. There are 2 ways to do it, typically on-chain program call Cross Program Invocation (CPI) to interact with each other, but we recommend using the Flash Fill method built by Jupiter.

Why Flash Fill?

With Jupiter's complex routing, best prices comes at a cost. It often means more compute resources and accounts are required as it would route across multiple DEXes in one transaction.

Solana transactions are limited to 1232 bytes, Jupiter is using Address Lookup Tables (ALTs) to include more accounts in one transaction. However, the CPI method cannot use ALTs, which means when you add more accounts to a Jupiter Swap transaction, it will likely fail if it exceeds the transaction size limits.

Flash Fill allows the use of Versioned Transaction and ALTs, hence, reducing the total accounts used for a Jupiter Swap transaction.

Flash Fill and CPI references
A Flash Fill transaction will be composed of these instructions:
  1. Borrow enough SOL for opening the wSOL account from this program.
  2. Create the wSOL account for the borrower.
  3. Swap X token to wSOL.
  4. Close the wSOL account and send it to the borrower.
  5. Repay the SOL for opening the wSOL account back to this program.
Links and resources: