For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Contact SupportDiscordGo to dashboard
HomeDocsAPI ReferenceLiquidity IntegrationChangelog
HomeDocsAPI ReferenceLiquidity IntegrationChangelog
  • Introduction
    • Welcome
    • Supported Chains and Providers
    • Demo Apps
    • FAQ
    • API Issues & Error Codes
    • Need Help?
  • Swap API
    • Introduction
    • FAQ
  • Gasless API
    • Introduction
    • Gasless FAQ
  • Solana Swap API
    • Introduction
      • Get Started
      • Important Integration Notes
      • Integrator Byte Costs
    • Gasless FAQ
  • Cross-Chain API
    • Introduction
    • Learn More
  • Trade Analytics API
    • Introduction
    • Transaction Data
    • Trade Analytics FAQ
  • Core Concepts
    • Introduction to 0x
    • 0x Cheat Sheet
    • Contracts
    • Order Types
    • Glossary
    • White Paper
    • Transaction Data
  • Developer Resources
    • Bounties
    • Rate Limits
    • System Status
  • Upgrading
    • Overview
    • Upgrading to Swap v2
    • Upgrading to Gasless v2
  • Need Help?
    • FAQ
    • API Issues & Error Codes
    • Contact Support
    • Contact Sales
LogoLogo
Contact SupportDiscordGo to dashboard
On this page
  • About 0x Solana Swap API
  • Steps to Swap Token
  • 0. Prerequisites
  • 1. Fetch a Quote
  • Example request
  • Required Request Parameters
  • Example Response
  • 2. Build Swap Instructions
  • What this does
  • 3. Resolve Address Lookup Tables
  • 4. Sign and Send the Transaction
  • Notes
  • sendTransaction Options
  • Transaction Confirmation
  • Important Integration Notes
Solana Swap APIGuides

Get Started

||View as Markdown|
Was this page helpful?
Edit this page
Previous

Introduction

Next

Important Integration Notes

Built with

The 0x Solana Swap API is available via priority access. Apply now to start building.

Quick link for example code: link

About 0x Solana Swap API

The 0x Solana Swap API is a fast, flexible API that lets developers programmatically access the best token prices across Solana’s top DEXs, enabling seamless swap functionality in any app or wallet.

Whether you’re building a Solana-native experience or expanding an EVM-first product, the API helps you integrate token swaps with minimal overhead and maximum performance.

Steps to Swap Token

This guide will walk you through using the /swap-instructions endpoint on 0x’s Solana API to:

  1. Fetch a quote
  2. Build the swap instructions
  3. Sign and send a VersionedTransaction on Solana mainnet

0. Prerequisites

Make sure you have:

  • 0x API key
  • A funded Solana keypair (see details below)
  • A RPC Connection (see details below)
Setup a keypair

To sign and send transactions on Solana, you’ll need a valid keypair that has funds to swap (e.g. SOL). This represents the “taker” account executing the swap. For testing purposes, you can generate a new keypair locally or use an existing one by loading the private key from an environment variable.

1import { Keypair } from "@solana/web3.js";
2import bs58 from "bs58";
3
4const takerKeypair = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY));
Security note: Avoid hardcoding or pasting private keys directly into source files. In production, always use secure key management tools or wallet adapters (e.g. Phantom, Backpack, Ledger, etc.).
Setup an RPC Connection

Solana provides a default public RPC endpoint, but for production use, it’s strongly recommended to run your own or use a third-party provider like Helius.

1import { Connection } from "@solana/web3.js";
2
3// You can replace this with your own or a third-party RPC URL
4const connection = new Connection("https://api.mainnet-beta.solana.com");

1. Fetch a Quote

Start by sending a POST request to the 0x /swap-instructions endpoint to get swap instructions for a specific token pair and input amount.

This endpoint returns everything needed to construct and execute a swap transaction.

Example request

1const quoteResponse = await fetch("https://api.0x.org/solana/swap-instructions", {
2 method: "POST",
3 headers: {
4 "0x-api-key": process.env.ZEROEX_API_KEY!,
5 "Content-Type": "application/json",
6 },
7 body: JSON.stringify({
8 token_out: "So11111111111111111111111111111111111111112", // SOL
9 token_in: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
10 amount_in: 100000000, // Amount of token_in in base units (e.g. 100 USDC)
11 taker: takerKeypair.publicKey.toBase58(), // Public key of wallet executing the swap
12 slippage_bps: 50, // default is 50 if omitted
13 }),
14});
15
16const quote = await quoteResponse.json();

Required Request Parameters

For the complete list of required request parameters, see the API Reference.

Example Response

For a sample response, complete schema, and detailed field descriptions, see the API Reference.

2. Build Swap Instructions

Once you have the quote, the response will include a list of serialized Solana instructions. These need to be deserialized into TransactionInstruction objects before you can add them to a transaction.

Each instruction includes:

  • A list of accounts (with signer/writable metadata)
  • A program ID
  • Raw instruction data

Here’s how to decode them using @solana/web3.js:

1import { TransactionInstruction, PublicKey } from "@solana/web3.js";
2
3function decodePubkey(bytes: number[]): PublicKey {
4 return new PublicKey(Uint8Array.from(bytes));
5}
6
7function buildInstructions(instructionsData: any[]): TransactionInstruction[] {
8 return instructionsData.map((ix) => {
9 const keys = ix.accounts.map((acc: any) => ({
10 pubkey: decodePubkey(acc.pubkey),
11 isSigner: acc.is_signer,
12 isWritable: acc.is_writable,
13 }));
14
15 const programId = decodePubkey(ix.program_id);
16 const data = Buffer.from(ix.data);
17
18 return new TransactionInstruction({ keys, programId, data });
19 });
20}
21
22const instructions = buildInstructions(quote.instructions);

What this does

  • Decodes each pubkey from byte array to a PublicKey
  • Reconstructs all TransactionInstruction objects needed to build your Solana transaction

3. Resolve Address Lookup Tables

Before you compile and sign a v0 (VersionedTransaction), you need to resolve any Address Lookup Tables (ALTs) returned by the 0x /swap-instructions endpoint.

ALTs let Solana v0 transactions reference more accounts than can fit in the static account list by “looking up” additional addresses on-chain. If the quote response includes address_lookup_tables, you must:

  1. Fetch each lookup table account from RPC
  2. Deserialize it into an AddressLookupTableAccount
  3. Pass the resulting accounts into compileToV0Message(...)
1import {
2 AddressLookupTableAccount,
3 PublicKey,
4} from "@solana/web3.js";
5
6// Fetch & deserialize Address Lookup Table accounts for v0 tx compilation
7async function resolveAddressLookupTables(
8 connection: any,
9 keys: string[]
10): Promise<AddressLookupTableAccount[]> {
11 const accountInfos = await connection.getMultipleAccountsInfo(
12 keys.map((key) => new PublicKey(key))
13 );
14
15 const accounts: AddressLookupTableAccount[] = [];
16 for (let i = 0; i < keys.length; i++) {
17 const accountInfo = accountInfos[i];
18 if (!accountInfo) {
19 throw new Error(`Failed to resolve address lookup table: ${keys[i]}`);
20 }
21
22 accounts.push(
23 new AddressLookupTableAccount({
24 key: new PublicKey(keys[i]),
25 state: AddressLookupTableAccount.deserialize(accountInfo.data),
26 })
27 );
28 }
29
30 return accounts;
31}

4. Sign and Send the Transaction

With your instructions ready, the final step is to wrap them in a VersionedTransaction, sign it with your wallet, and send it to the Solana network.

The 0x Solana API returns instructions that are compatible with the latest v0 transaction format, which supports address deduplication and future extensions.

1import {
2 Connection,
3 Keypair,
4 VersionedTransaction,
5 TransactionMessage,
6} from "@solana/web3.js";
7
8const latestBlockhash = await connection.getLatestBlockhash();
9
10const instructions = buildInstructions(quote.instructions);
11const [addressLookupTableAccounts, latestBlockhash] = await Promise.all([
12 resolveAddressLookupTables(quote.address_lookup_tables ?? []),
13 config.connection.getLatestBlockhash(),
14]);
15
16const messageV0 = new TransactionMessage({
17 payerKey: takerKeypair.publicKey,
18 recentBlockhash: latestBlockhash.blockhash,
19 instructions,
20}).compileToV0Message(addressLookupTableAccounts);
21
22const versionedTx = new VersionedTransaction(messageV0);
23versionedTx.sign([takerKeypair]);
24
25const signature = await connection.sendTransaction(versionedTx, {
26 skipPreflight: true,
27});
28
29const confirmation = await connection.confirmTransaction(
30 {
31 signature,
32 blockhash: latestBlockhash.blockhash,
33 lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
34 },
35 "finalized",
36);
37
38console.log(`✅ Swap complete: https://solscan.io/tx/${signature}`);

Notes

  • The transaction must be signed by the taker (payer of the swap)
  • You’ll need a funded wallet that can cover gas (SOL)
  • If you add extra instructions (compute budget, unwrap/cleanup, transfers, etc.), be mindful of the v0 transaction 1232-byte limit and use the Integrator Byte Costs guide to reserve bytes appropriately.

sendTransaction Options

When sending the signed transaction to the Solana network, there are a couple of important options you can configure to control how the RPC node handles it. These options can impact performance, reliability, and UX depending on your use case.

1const signature = await connection.sendTransaction(versionedTx, {
2 maxRetries: 3,
3 skipPreflight: false,
4});
OptionDescription

maxRetries

Maximum number of times the RPC node will retry sending the transaction to the leader. If omitted, it retries until finalized or blockhash expires.

skipPreflight

If true, skips the preflight checks before sending (default is false), specifically:

  • Verify that all signatures are valid
  • Check that the referenced blockhash is within the last 150 blocks

  • Simulate the transaction against the block slot specified by the preflightCommitment

For example, if your use case is a payment solution where reliability is more important than speed, you might set a higher maxRetries to ensure the transaction has multiple attempts. For a fast-moving trading bot, you might prefer to set skipPreflight=true to reduce latency.

Transaction Confirmation

In addition, after sending the transaction, it is always best practice to check the transaction confirmation state. If the transaction fails, you should log the error for debugging or communicate it clearly with your users on your interface.

You can confirm the transaction using the confirmTransaction method with your chosen level of commitment - "finalized" , "confirmed", or "processed". Learn more about configuring state commitment levels to choose the right option for your use case.

1const confirmation = await connection.confirmTransaction(
2 {
3 signature,
4 blockhash: latestBlockhash.blockhash,
5 lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
6 },
7 "confirmed",
8);
9
10if (confirmation.value.err) {
11 throw new Error(
12 `Transaction failed: ${JSON.stringify(confirmation.value.err)}\nhttps://solscan.io/tx/${signature}/`,
13 );
14} else {
15 console.log(`Transaction successful: https://solscan.io/tx/${signature}/`);
16}

For additional best practices on confirming transactions and handling errors, see the transaction confirmation tips guide.

Important Integration Notes

Coming from another swap provider? Make sure to review the following:

[TODO]