> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.0x.org/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.0x.org/_mcp/server.

# Create Swap Instructions

POST https://api.0x.org/solana/swap-instructions
Content-Type: application/json

Returns Solana swap instructions for a given token pair and amount.

Reference: https://docs.0x.org/api-reference/solana-swap-ap-is/swap/instructions

## Request

### Headers

- `0x-api-key` (string, required) — Visit dashboard.0x.org to get your API Key

### Body (application/json)

- `amount_in` (long, required) — Input amount in its base units.
- `taker` (string, required) — Base-58 encoded taker wallet address.
- `token_in` (string, required) — Input token mint, base-58 encoded. Use `So11111111111111111111111111111111111111111` for native SOL.
- `token_out` (string, required) — Output token mint, base-58 encoded. Use `So11111111111111111111111111111111111111111` for native SOL.
- `disabled_sources` (list of string, optional) — DEX sources to exclude from routing. Valid source names are returned by `/enabled-sources`.
- `recipient` (string or object, optional, nullable) — A swap destination: either an existing token account (or wallet for native SOL) address, or an owner whose token account should be used, and created if required. If an account is created, its rent is paid by `sponsor` if present, else by `taker`. If the created ATA belongs to the taker, the sponsor keeps close authority and can reclaim the rent once the account is empty. ATAs created for anyone else (custom recipient, fee or surplus recipient) leave the rent as a permanent sponsor cost.
  - object
    - `associatedTokenAccount` (object, required)
      - `owner` (string, required) — Base-58 encoded owner address that the created token account belongs to.
- `reserve_transaction_bytes` (long, optional, default: 0) — Minimum bytes to reserve in the transaction for composing with additional instructions.
- `slippage_bps` (integer, optional, default: 50) — Slippage tolerance in basis points.
- `sponsor` (string, optional) — Transaction fee payer and rent payer for a fully-sponsored swap. Must differ from the taker and from every native destination in the request. The taker remains the swap authority and must still sign.
- `swap_fee_ppm` (string, optional) — Comma-separated volume-based swap fees in parts per million. Must be provided together with `swap_fee_recipient`. Each entry must be between `0` and the per-app maximum (`100_000` unless configured otherwise). A value of `0` disables that fee entry. Multiple fees on the same side are applied sequentially, each on the amount remaining after prior deductions — not the original amount. Fee amounts are rounded up to the nearest base unit.
- `swap_fee_recipient` (string or list of string or object, optional, nullable) — Fee recipients for the swap fees: either a comma-separated list of existing token accounts, or a structured list mixing addresses with owners whose token accounts should be the fee recipient.
- `swap_fee_side` (string, optional) — Comma-separated fee sides for each fee entry. Supported values are `buy` and `sell`. This field may be omitted only when every fee uses the default `buy` side. When provided, the number of entries must match `swap_fee_ppm`.
- `trade_surplus_cap_ppm` (integer, optional) — Trade surplus cap in parts per million of the total realized trade size. Must be provided together with `trade_surplus_recipient`, or both fields must be omitted. A value of `0` disables trade surplus collection for the request. When 0x controls trade surplus collection, the request value is ignored and the configured 0x policy is applied instead. The transferred amount is capped relative to trade size.
- `trade_surplus_recipient` (string or object, optional, nullable) — A swap destination: either an existing token account (or wallet for native SOL) address, or an owner whose token account should be used, and created if required. If an account is created, its rent is paid by `sponsor` if present, else by `taker`. If the created ATA belongs to the taker, the sponsor keeps close authority and can reclaim the rent once the account is empty. ATAs created for anyone else (custom recipient, fee or surplus recipient) leave the rent as a permanent sponsor cost.
  - object
    - `associatedTokenAccount` (object, required)
      - `owner` (string, required) — Base-58 encoded owner address that the created token account belongs to.

## Response

### 200

Swap instructions

- `address_lookup_tables` (list of string, required) — Address Lookup Table addresses that must be included in the versioned transaction.
- `amount_out` (long, required) — The estimated output amount after fees, in its base units.
- `instructions` (list of object, required) — The instructions to perform the swap.
  - `accounts` (list of object, required)
    - `is_signer` (boolean, required)
    - `is_writable` (boolean, required)
    - `pubkey` (list of integer, required) — Account public key as a 32-byte array.
  - `data` (list of integer, required) — Serialized instruction data bytes.
  - `program_id` (list of integer, required) — Program ID as a 32-byte array.
- `min_amount_out` (long, required) — The minimum output amount after slippage and fees, in its base units. Transaction will fail if this amount is not met.
- `route_plan` (list of object, required) — List of swap legs comprising the swap.
  - `amount_in` (string, required) — The amount of the input token to swap, in its base units.
  - `amount_out` (string, required) — The estimated amount of the output token received from the swap, in its base units.
  - `dex_address` (string, required) — The base-58 encoded address of the DEX.
  - `dex_label` (string, required) — The label for the DEX. Matches labels returned by the `enabled-sources` endpoint.
  - `dex_program_id` (string, required) — The base-58 encoded program ID address of the DEX.
  - `ppb` (integer, required) — Proportion of _remaining_ amount routed through this step in parts per billion.
  - `token_in` (string, required) — The base-58 encoded address of the input mint.
  - `token_out` (string, required) — The base-58 encoded address of the output mint.
- `zid` (string, required) — Unique 12-byte hex identifier for this request.
- `sponsor` (string, optional) — Present when the caller requested full sponsorship. The returned transaction must use this address as fee payer; both sponsor and taker sign.

## Examples

**Request**

```json
{
  "amount_in": 1000000000,
  "taker": "ZeroEx1111111111111111111111111111111111111",
  "token_in": "So11111111111111111111111111111111111111112",
  "token_out": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "slippage_bps": 50
}
```

**Response**

```json
{
  "address_lookup_tables": [
    "string"
  ],
  "amount_out": 1,
  "instructions": [
    {
      "accounts": [
        {
          "is_signer": true,
          "is_writable": true,
          "pubkey": [
            1
          ]
        }
      ],
      "data": [
        1
      ],
      "program_id": [
        1
      ]
    }
  ],
  "min_amount_out": 1,
  "route_plan": [
    {
      "amount_in": "string",
      "amount_out": "string",
      "dex_address": "string",
      "dex_label": "string",
      "dex_program_id": "string",
      "ppb": 1,
      "token_in": "string",
      "token_out": "string"
    }
  ],
  "zid": "string",
  "sponsor": "string"
}
```

**SDK Code**

```python
import requests

url = "https://api.0x.org/solana/swap-instructions"

payload = {
    "amount_in": 1000000000,
    "taker": "ZeroEx1111111111111111111111111111111111111",
    "token_in": "So11111111111111111111111111111111111111112",
    "token_out": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "slippage_bps": 50
}
headers = {
    "0x-api-key": "0x-api-key",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.0x.org/solana/swap-instructions';
const options = {
  method: 'POST',
  headers: {'0x-api-key': '0x-api-key', 'Content-Type': 'application/json'},
  body: '{"amount_in":1000000000,"taker":"ZeroEx1111111111111111111111111111111111111","token_in":"So11111111111111111111111111111111111111112","token_out":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","slippage_bps":50}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.0x.org/solana/swap-instructions"

	payload := strings.NewReader("{\n  \"amount_in\": 1000000000,\n  \"taker\": \"ZeroEx1111111111111111111111111111111111111\",\n  \"token_in\": \"So11111111111111111111111111111111111111112\",\n  \"token_out\": \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\n  \"slippage_bps\": 50\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("0x-api-key", "0x-api-key")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.0x.org/solana/swap-instructions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["0x-api-key"] = '0x-api-key'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"amount_in\": 1000000000,\n  \"taker\": \"ZeroEx1111111111111111111111111111111111111\",\n  \"token_in\": \"So11111111111111111111111111111111111111112\",\n  \"token_out\": \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\n  \"slippage_bps\": 50\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.0x.org/solana/swap-instructions")
  .header("0x-api-key", "0x-api-key")
  .header("Content-Type", "application/json")
  .body("{\n  \"amount_in\": 1000000000,\n  \"taker\": \"ZeroEx1111111111111111111111111111111111111\",\n  \"token_in\": \"So11111111111111111111111111111111111111112\",\n  \"token_out\": \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\n  \"slippage_bps\": 50\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.0x.org/solana/swap-instructions', [
  'body' => '{
  "amount_in": 1000000000,
  "taker": "ZeroEx1111111111111111111111111111111111111",
  "token_in": "So11111111111111111111111111111111111111112",
  "token_out": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "slippage_bps": 50
}',
  'headers' => [
    '0x-api-key' => '0x-api-key',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.0x.org/solana/swap-instructions");
var request = new RestRequest(Method.POST);
request.AddHeader("0x-api-key", "0x-api-key");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"amount_in\": 1000000000,\n  \"taker\": \"ZeroEx1111111111111111111111111111111111111\",\n  \"token_in\": \"So11111111111111111111111111111111111111112\",\n  \"token_out\": \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\",\n  \"slippage_bps\": 50\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "0x-api-key": "0x-api-key",
  "Content-Type": "application/json"
]
let parameters = [
  "amount_in": 1000000000,
  "taker": "ZeroEx1111111111111111111111111111111111111",
  "token_in": "So11111111111111111111111111111111111111112",
  "token_out": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "slippage_bps": 50
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.0x.org/solana/swap-instructions")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```