# Cross-Chain Calls
Source: https://docs.swaps.xyz/guides/calldata-call
Execute cross-chain transactions.
**API Reference:** [Get Action](/swap-api-reference/get-action#swap)
This guide will only cover the process of generating calldata transactions. You can submit this transaction exactly as outlined in the [swap broadcast flows](/guides/swap#broadcast-on-evm).
## Create a cross-chain transaction
In this example, we are going to deposit 1 ETH liquidity in Aave on Base using USDC on Arbitrum.
We'll use helper functions from [Viem](https://viem.sh/); however, you can use your preferred library.
```typescript theme={null}
import { account, walletClient } from "./your_viem_config";
import { encodeFunctionData, parseAbiItem, Hex } from "viem";
const aaveOnBase = "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5";
const ethDepositAmount = 1000000000000000000n;
const sender = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"; // generally the user's connected wallet address
const supplyTxCalldata: Hex = encodeFunctionData({
abi: parseAbiItem(
"function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)"
),
functionName: "supply",
args: [
"0x0000000000000000000000000000000000000000",
ethDepositAmount,
sender,
0n,
],
});
```
Cross-chain calls can handle all non-permissioned functions. If your function
includes a `msg.sender` check, please consider updating it to a multi-chain
compatible sender authentication method based on [this
guide](/resources/best-practices#manage-permissioned-functions).
**Calldata Transaction Config**
```typescript theme={null}
const txConfig: ActionRequest = {
actionType: "evm-calldata-tx",
sender,
srcToken: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", // USDC on Arbitrum
dstToken: "0x0000000000000000000000000000000000000000", // ETH on Base
srcChainId: 42161, // Arbitrum Chain ID
dstChainId: 8453, // Base Chain ID
slippage: 100, // bps
to: aaveOnBase,
data: supplyTxCalldata,
value: ethDepositAmount,
};
```
Please visit the [Get Action](/swap-api-reference/get-action) API reference for type definitions, including the `ActionRequest` and `ActionResponse`. This API endpoint will return a transaction object we will use to actually execute this transaction.
```typescript theme={null}
async function getAction({ actionRequest }): Promise {
const url = new URL("https://api-v2.swaps.xyz/api/getAction");
Object.entries(actionRequest).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
}
const requestOptions = {
method: "GET",
headers: { "x-api-key": SWAPS_API_KEY },
};
const response = await fetch(url.toString(), requestOptions);
return await response.json();
}
```
**That's it!** You now have a transaction you can broadcast on your source
chain. Please see the [swap broadcast flows](/guides/swap#broadcast-on-evm)
for how you can send this transaction on chain.
# Gasless Transactions
Source: https://docs.swaps.xyz/guides/preview/gasless
Execute sponsored meta-transactions without requiring users to hold native tokens for gas.
**API Reference:** [GET /getAction](/swap-api-reference/get-action) · [POST /submitTx](/swap-api-reference/submit-gasless-transaction)
This guide extends the standard [Swaps.xyz swap flow](https://docs.swaps.xyz/guides/swap) with optional gasless execution.
## Overview
Gasless transactions allow users to execute swaps without paying gas fees directly. When `gasless=true` is passed to `getAction`, the API returns a set of signing steps (`executions`) instead of a raw transaction. The user signs each step and submits them to `POST /submitTx`, which handles relay and broadcast.
**Supported Chains:** Tron same-chain swaps only (cross-chain and EVM chains coming soon)
Gasless execution requires your API key to have gasless enabled. Contact the Swaps team if you need access.
***
## Requesting Gasless Execution
Add the optional `gasless` query parameter to your `getAction` request:
```typescript theme={null}
const params = new URLSearchParams({
actionType: "swap-action",
sender: "TRiskt1RqdWMfvWEU8CMxSBh3MPSPP9UoL",
srcToken: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // USDT on Tron
dstToken: "0x0000000000000000000000000000000000000000", // TRX on Tron
srcChainId: "728126428",
dstChainId: "728126428",
slippage: "100",
swapDirection: "exact-amount-in",
amount: "1000000",
recipient: "TRiskt1RqdWMfvWEU8CMxSBh3MPSPP9UoL",
gasless: "true", // ← Request gasless execution
});
const actionResponse = await fetch(
`https://api-v2.swaps.xyz/api/getAction?${params}`,
{ headers: { "x-api-key": YOUR_API_KEY } }
).then((r) => r.json());
```
> **Note:** Omit `gasless` or set it to `false` for standard transactions.
***
## Understanding the Response
When `gasless=true` is requested and a relay provider is available for the source chain, the response includes:
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `executionsType` | `"GASLESS"` — indicates relay execution |
| `executions` | Ordered array of signing steps |
| `relayerFee` | Fee charged by the relay, denominated in USDT. If non-zero, the user must hold USDT in addition to the source token |
| `txId` | Unique action ID returned by `getAction` — required when calling `POST /submitTx` |
```typescript theme={null}
// Example gasless getAction response (simplified)
{
txId: "0xabc123...",
executionsType: "GASLESS",
relayerFee: { amount: "5000000", token: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", ... },
executions: [
// Step 1 (if needed): approve relay fee transfer
{
txType: "evmTransactionSign",
data: "{...unsigned Tron transaction JSON...}"
},
// Step 2: sign the swap meta-transaction
{
txType: "evmSignTypedData",
data: {
domain: { name: "SunSwapProxy", version: "1", chainId: 728126428, verifyingContract: "..." },
types: { MetaTransaction: [{ name: "nonce", type: "uint256" }, ...] },
message: { nonce: 0, from: "0x...", functionSignature: "0x..." }
}
}
],
// ... standard fields: amountIn, amountOut, tx, etc.
}
```
If `executionsType` is `"DEFAULT"` (relay unavailable or `gasless` not set), broadcast `tx` directly as a standard transaction — see the [swap guide](https://docs.swaps.xyz/guides/swap).
***
## Executing Gasless Transactions
Always check the response before proceeding:
```typescript theme={null}
if (actionResponse.executionsType !== "GASLESS") {
// Fall back to standard broadcast
return broadcastStandardTx(actionResponse.tx);
}
```
Iterate `executions` and sign each step with the appropriate wallet method:
```typescript theme={null}
const signedExecutions = await Promise.all(
actionResponse.executions.map(async (execution) => {
if (execution.txType === "evmTransactionSign") {
// Sign an unsigned Tron transaction
const unsignedTx = JSON.parse(execution.data);
const signedTx = await tronWeb.trx.sign(unsignedTx);
return {
...execution,
signature: signedTx.signature[0],
data: JSON.stringify(signedTx),
};
}
if (execution.txType === "evmSignTypedData") {
// Sign EIP-712 typed data (swap meta-transaction)
const { domain, types, message } = execution.data;
const signature = await tronWeb.trx.signTypedData(domain, types, message);
return { ...execution, signature };
}
return execution;
})
);
```
> **Order matters.** Fee approval steps (if present) must be signed and submitted before the swap step. The array is already in the correct order.
Send the signed executions along with the `txId` from the `getAction` response:
```typescript theme={null}
const submitResponse = await fetch("https://api-v2.swaps.xyz/api/submitTx", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": YOUR_API_KEY,
},
body: JSON.stringify({
txId: actionResponse.txId,
chainId: 728126428, // srcChainId
executions: signedExecutions,
}),
});
const result = await submitResponse.json();
// { success: true, txId: "internal-tx-id" }
// Pass txId to GET /getStatus to poll for the on-chain transaction hash
```
***
## Complete Example
```typescript theme={null}
const YOUR_API_KEY = "...";
const TRON_CHAIN_ID = 728126428;
// 1. Request gasless action
const params = new URLSearchParams({
actionType: "swap-action",
sender: "TRiskt1RqdWMfvWEU8CMxSBh3MPSPP9UoL",
srcToken: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
dstToken: "0x0000000000000000000000000000000000000000",
srcChainId: String(TRON_CHAIN_ID),
dstChainId: String(TRON_CHAIN_ID),
slippage: "100",
swapDirection: "exact-amount-in",
amount: "1000000",
recipient: "TRiskt1RqdWMfvWEU8CMxSBh3MPSPP9UoL",
gasless: "true",
});
const actionResponse = await fetch(
`https://api-v2.swaps.xyz/api/getAction?${params}`,
{ headers: { "x-api-key": YOUR_API_KEY } }
).then((r) => r.json());
// 2. Fall back to standard flow if relay unavailable
if (actionResponse.executionsType !== "GASLESS") {
return broadcastStandardTx(actionResponse.tx);
}
// 3. Sign each execution in order
const signedExecutions = await Promise.all(
actionResponse.executions.map(async (execution) => {
if (execution.txType === "evmTransactionSign") {
const unsignedTx = JSON.parse(execution.data);
const signedTx = await tronWeb.trx.sign(unsignedTx);
return { ...execution, signature: signedTx.signature[0], data: JSON.stringify(signedTx) };
}
if (execution.txType === "evmSignTypedData") {
const { domain, types, message } = execution.data;
const signature = await tronWeb.trx.signTypedData(domain, types, message);
return { ...execution, signature };
}
return execution;
})
);
// 4. Submit for relay broadcast
const { success, txId } = await fetch("https://api-v2.swaps.xyz/api/submitTx", {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": YOUR_API_KEY },
body: JSON.stringify({
txId: actionResponse.txId,
chainId: TRON_CHAIN_ID,
executions: signedExecutions,
}),
}).then((r) => r.json());
// Poll GET /getStatus with txId to get the on-chain transaction hash
console.log(`Relay accepted. Poll getStatus with txId: ${txId}`);
```
***
## Notes
* **Standard fallback:** Always check `executionsType` — if `"DEFAULT"`, broadcast `tx` directly (see [swap guide](https://docs.swaps.xyz/guides/swap)).
* **Error handling:** `POST /submitTx` validates signatures and simulates transactions before broadcasting. A `400` response indicates a bad signature or expired `txId`.
* **Relayer fee:** The `relayerFee` field shows the fee deducted from `amountIn` to pay the relay. Display it to users alongside the swap quote.
***
## Type Definitions
```typescript theme={null}
type ExecutionTxType = "evmTransactionSign" | "evmSignTypedData";
interface BaseExecution {
txType: ExecutionTxType;
signature: string; // populated by the client after signing
}
interface EvmTransactionSignExecution extends BaseExecution {
txType: "evmTransactionSign";
data: string; // JSON string of unsigned transaction (TronWeb raw_data shape for Tron)
}
interface EvmSignTypedDataExecution extends BaseExecution {
txType: "evmSignTypedData";
// Accepted as a JSON string (verbatim from getAction) or a parsed object — both are equivalent.
data: string | Eip712Data;
}
type Execution = EvmTransactionSignExecution | EvmSignTypedDataExecution;
interface Eip712Data {
domain: { name: string; version: string; chainId: number; verifyingContract: string };
types: Record;
message: Record;
}
interface SubmitTxRequest {
txId: string;
chainId: number;
executions: Execution[];
}
interface SubmitTxResponse {
success: boolean;
txId?: string; // internal ID — pass to GET /getStatus to get the on-chain transaction hash
error?: string;
}
```
# Stableswaps
Source: https://docs.swaps.xyz/guides/stableswaps
Tighter pricing on stablecoin pairs through a dedicated stable-pair router — no new parameters or endpoints.
Swaps runs a dedicated stableswap protocol that prices
stablecoin-to-stablecoin trades far tighter than general-purpose DEX routing.
It is fully transparent to integrators: request a supported stable pair
through [`GET /getAction`](/swap-api-reference/get-action) and Swaps
automatically routes through the stableswap venue when it wins on price.
There are no new parameters and no new endpoints.
## Supported scope
Live today on **Solana mainnet**, for any pair among:
| Token | Mint |
| ----- | ---------------------------------------------- |
| USDC | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |
| USDT | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` |
| PYUSD | `2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo` |
| xoUSD | `xoUSDq85Rjsb6SbUwJyreFgeWQvxdkT7R3c3g7s6p5Y` |
Stableswap routes support **sponsorship**: pass the standard `solanaSponsor`
parameter and the sponsor covers transaction fees and rent on behalf of the
user, making the swap gasless from the user's perspective.
## Example
A same-chain Solana swap from USDC to PYUSD — a standard `getAction` request:
```bash theme={null}
curl "https://api-v2.swaps.xyz/api/getAction?\
actionType=swap-action&\
sender=&\
srcChainId=1399811149&\
srcToken=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&\
dstChainId=1399811149&\
dstToken=2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo&\
amount=100000000&\
swapDirection=exact-amount-in&\
slippage=100&\
recipient=" \
-H "x-api-key: $API_KEY"
```
The response is a standard `ActionResponse` with a serialized Solana
transaction to sign and broadcast. When the stableswap venue offers the best
execution for the pair, Swaps selects it automatically — the request and
response shapes are identical either way.
## Tracking
Stableswaps are tracked like any other swap: poll
[`GET /getStatus`](/swap-api-reference/get-status) with the `txId` or use
[webhooks](/guides/track-transactions).
## Direct integration
Routing over the stableswap venues at the contract level — for example, as a
DEX aggregator plugging on-chain liquidity into your own routing graph? See
the [Protocol Reference](/protocol-reference/overview).
# Swap
Source: https://docs.swaps.xyz/guides/swap
Generate and broadcast a swap or bridge transaction.
**API Reference:** [Get Action](/swap-api-reference/get-action#swap)
Submitting transactions differs by source chain VM. Reference available transaction types [here](/swap-api-reference/get-action#response-tx).
**Examples below demonstrate the swap process for each VM.**
VmId: evm, solana,
alt-vm
(any non-named VM - e.g., Bitcoin, Ripple).
## Create a swap transaction
The Swap action type covers same chain swaps, bridge, and cross-chain swap
transactions. Swaps are all just swaps!
**The `recipient` should only be different from the `sender` if you are:**
1. Swapping across VMs that use incompatible key formats or cryptographic curves (e.g., `EVM <> Solana`)
2. Sending funds to another address
This example prepares a swap from [USDC on Base](https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913) to [USDT on Arbitrum](https://arbiscan.io/token/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9). To transact across non-EVM networks, simply update the chainId and token fields to your desired pairs, no further customizations required.
```typescript theme={null}
import { sendTransaction } from "@wagmi/core";
import { useAccount } from "wagmi";
const actionRequest = {
actionType: "swap-action",
sender: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // generally the user's connected wallet address
srcToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // USDC on Base
dstToken: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", // USDT on Arbitrum
srcChainId: 8453, // Base Chain ID
dstChainId: 42161, // Arbitrum Chain ID
slippage: 100, // bps
swapDirection: "exact-amount-in",
amount: 10000000n, // denominated in srcToken decimals
recipient: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
};
```
Please visit the [Get Action](/swap-api-reference/get-action) API reference for type definitions, including the `ActionRequest` and `ActionResponse`. This API endpoint will return a transaction object we will use to actually execute this transaction.
```typescript theme={null}
import { sendTransaction } from "@wagmi/core";
import { useAccount } from "wagmi";
const actionRequest: ActionRequest = {
actionType: "swap-action",
sender: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // generally the user's connected wallet address
srcToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // USDC on Base
dstToken: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", // USDT on Arbitrum
srcChainId: 8453, // Base Chain ID
dstChainId: 42161, // Arbitrum Chain ID
slippage: 100, // bps
swapDirection: "exact-amount-in",
amount: 10000000n, // denominated in srcToken decimals
recipient: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
};
async function getAction({ actionRequest }): Promise {
const url = new URL("https://api-v2.swaps.xyz/api/getAction");
Object.entries(actionRequest).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
});
const requestOptions = {
method: "GET",
headers: { "x-api-key": SWAPS_API_KEY },
};
const response = await fetch(url.toString(), requestOptions);
return await response.json();
}
```
**That's it!** You now have a transaction you can broadcast on your source
chain.
## Broadcast on EVM
In this step, we will broadcast the transaction we generated above on Base. This method will work for any EVM chain.
View the EVM transaction type [here](/swap-api-reference/get-action#evm-transaction).
This example uses [Wagmi](https://wagmi.sh/); however, you can use your preferred provider. The transaction we'll generate is compatible with any library.
```typescript theme={null}
import { useAccount } from "wagmi";
import { sendTransaction, estimateGas } from "@wagmi/core";
import { wagmiConfig } from "../your_wagmi_config_path";
```
If your source token is an ERC20, you will have to first submit a token
approval. We recommend only approving the amount required for the transaction.
Please follow the guide [here](/guides/token-approvals).
```typescript theme={null}
import { sendTransaction, estimateGas } from "@wagmi/core";
import { arbitrum, base } from "viem/chains";
import { wagmiConfig } from "../your_wagmi_config_path";
export async function broadcastOnEvm({ actionRequest }): Promise {
const account = useAccount({ config: wagmiConfig });
const { tx } = await getAction({ actionRequest });
const gas = await estimateGas(wagmiConfig, { account, ...tx });
const txHash = await sendTransaction(wagmiConfig, {
...tx,
gas,
});
return txHash;
}
```
**Transaction broadcasted!** Use [Basescan](https://basescan.org/) to verify your transaction.
## Broadcast on Solana
Let's assume we set Solana as the source chain in the `actionRequest` used to generate our transaction. Let's see how we can broadcast it on Solana.
View the Solana transaction type [here](/swap-api-reference/get-action#solana-transaction).
We'll use `@solana/web3.js`, which is the standard SDK for interacting with the Solana blockchain.
```typescript theme={null}
import {
Connection,
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
```
Ensure that the sender wallet has enough SOL to cover transaction fees. If the
swap involves a token account that doesn't exist yet, your transaction must include
an instruction to create it.
```typescript theme={null}
import {
Connection,
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
export async function broadcastOnSolana({ actionRequest }): Promise {
const { tx } = await getAction({ actionRequest });
const connection = new Connection("https://api.mainnet-beta.solana.com");
const senderKeypair = ... // Your wallet's keypair (use secure storage)
const transaction = Transaction.from(Buffer.from(tx.rawTransaction, "base64"));
const signature = await sendAndConfirmTransaction(connection, transaction, [senderKeypair]);
return signature;
}
```
**Transaction broadcasted!** Use a Solana explorer like [Solscan](https://solscan.io) to verify your transaction.
## Broadcast on Alt VMs
Let's assume we set Bitcoin as the source chain in the `actionRequest` used to generate our transaction. Let's see how we can broadcast it on Bitcoin.
View the alt VM transaction type [here](/swap-api-reference/get-action#alt-vm-transaction).
Alt VM transactions are all deposits: the transaction will transfer funds from
the `sender` to the `to` field specified in the `AltVmTransaction` response.
This transfer triggers the swap transaction and funds will ultimately be
delivered to the `recipient`.
Please note XRP Ledger requires an extra memo tag to submit transactions. This
is included in the `tx` response object.
Alt VM transactions require an extra step to track the status of transactions.
**See the required step**
[here](/guides/track-transactions#register-transaction).
```bash theme={null}
pnpm i bitcoinjs-lib
```
We’ll use bitcoinjs-lib to sign the Bitcoin transaction.
```typescript theme={null}
import * as bitcoin from "bitcoinjs-lib";
```
This example provides sample code to construct a Bitcoin transaction given the `actionResponse` transaction object and broadcast it to the network.
```typescript sendBtcTx.ts theme={null}
import { prepareBtcTx } from "./prepareBtcTx";
export async function sendTransaction() {
const { tx } = await getAction({ actionRequest });
const privateKeyWIF = "YOUR_PRIVATE_KEY_IN_WIF_FORMAT";
const keyPair = ECPair.fromWIF(privateKeyWIF, NET);
const payment = bitcoin.payments.p2wpkh({
pubkey: keyPair.publicKey,
network: NET,
});
const utxos = await getUtxosForAddress(payment.address);
const rawTransaction = prepareBtcTx({
tx,
privateKeyWIF,
utxos,
feeRate: 15,
});
const response = await fetch("https://blockstream.info/api/tx", {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: rawTransaction,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Broadcast failed: ${response.status} - ${errorText}`);
}
return await response.text();
}
```
```typescript prepareBtcTx.ts theme={null}
import * as bitcoin from "bitcoinjs-lib";
import * as ecc from "tiny-secp256k1";
import { ECPairFactory } from "ecpair";
bitcoin.initEccLib(ecc);
const ECPair = ECPairFactory(ecc);
const NET = bitcoin.networks.bitcoin;
const P2WPKH_DUST = 294;
const RBF_SEQUENCE = 0xfffffffd;
interface UTXO {
txid: string;
vout: number;
value: number;
address: string;
}
interface TxData {
to: string;
value: string;
chainId: number;
chainKey: string;
}
function estimateVsize(inputs: number, outputs: number): number {
return 10 + 68 * inputs + 31 * outputs;
}
function selectUtxos(utxos: UTXO[], target: number) {
const selected = [];
let total = 0;
for (const utxo of utxos) {
selected.push(utxo);
total += utxo.value;
if (total >= target) break;
}
return { selected, total };
}
export function prepareBtcTx({
tx,
privateKeyWIF,
utxos,
feeRate = 15,
}: {
tx: TxData;
privateKeyWIF: string;
utxos: UTXO[];
feeRate?: number;
}): string {
const outputValue = Number.parseInt(tx.value, 10);
if (!Number.isFinite(outputValue) || outputValue <= 0) {
throw new Error(`Invalid tx.value: ${tx.value}`);
}
// Validate destination address
bitcoin.address.toOutputScript(tx.to, NET);
// Derive change address
const keyPair = ECPair.fromWIF(privateKeyWIF, NET);
const payment = bitcoin.payments.p2wpkh({
pubkey: keyPair.publicKey,
network: NET
});
if (!payment.address) {
throw new Error("Could not derive P2WPKH address from private key");
}
// Estimate fee and select UTXOs
const vsize2 = estimateVsize(utxos.length, 2);
const fee2 = Math.ceil(vsize2 * feeRate);
let target = outputValue + fee2;
let { selected, total } = selectUtxos(utxos, target);
// If insufficient, try with single output (no change)
if (total < target) {
const vsize1 = estimateVsize(utxos.length, 1);
const fee1 = Math.ceil(vsize1 * feeRate);
const target1 = outputValue + fee1;
const retry = selectUtxos(utxos, target1);
if (retry.total < target1) {
throw new Error(`Insufficient funds. Need ${target1} sats, have ${retry.total}`);
}
selected = retry.selected;
total = retry.total;
}
// Calculate final outputs
const inputsCount = selected.length;
const feeTwoOut = Math.ceil(estimateVsize(inputsCount, 2) * feeRate);
let change = total - outputValue - feeTwoOut;
// Handle dust change
if (change > 0 && change < P2WPKH_DUST) {
const feeOneOut = Math.ceil(estimateVsize(inputsCount, 1) * feeRate);
change = total - outputValue - feeOneOut;
if (change < 0) {
throw new Error("Fee calculation error");
}
}
// Build transaction
const psbt = new bitcoin.Psbt({ network: NET });
// Add inputs
for (const utxo of selected) {
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
sequence: RBF_SEQUENCE,
witnessUtxo: {
script: bitcoin.address.toOutputScript(utxo.address, NET),
value: utxo.value,
},
});
}
// Add outputs
psbt.addOutput({ address: tx.to, value: outputValue });
if (change >= P2WPKH_DUST) {
psbt.addOutput({ address: payment.address, value: change });
}
// Sign all inputs
for (let i = 0; i < selected.length; i++) {
psbt.signInput(i, keyPair);
}
psbt.finalizeAllInputs();
return psbt.extractTransaction().toHex();
}
```
**Transaction broadcasted!** Use a Bitcoin explorer like [Blockstream](https://blockstream.info) to verify your transaction.
## Broadcast on HyperCore
Let's assume we set HyperCore as the source chain in the `actionRequest` used to generate our transaction. Let's see how we can broadcast it on HyperCore.
View the HyperCore transaction type [here](/swap-api-reference/get-action#hypercore-transaction).
```bash theme={null}
pnpm i @nktkas/hyperliquid viem
```
We'll use the HyperLiquid SDK for interacting with the HyperCore network.
```typescript theme={null}
import * as HyperLiquid from "@nktkas/hyperliquid";
import { createWalletClient, custom } from "viem";
```
Ensure that your wallet has sufficient balance to cover the transaction amount
and any associated fees on the HyperCore network.
```typescript theme={null}
import * as HyperLiquid from "@nktkas/hyperliquid";
import { createWalletClient, custom } from "viem";
export async function broadcastOnHyperCore({ actionRequest }): Promise {
const { tx } = await getAction({ actionRequest });
const [account] = await window.ethereum.request({
method: "eth_requestAccounts",
});
const wallet = createWalletClient({
account,
transport: custom(window.ethereum),
});
const transport = new HyperLiquid.HttpTransport();
const exchClient = new HyperLiquid.ExchangeClient({ wallet, transport });
return await exchClient.usdSend({
destination: tx.destination,
amount: tx.amount,
});
}
```
**Transaction broadcasted!** Use the [HyperLiquid explorer](https://app.hyperliquid.xyz/explorer) to verify your transaction.
# EVM Token Approvals
Source: https://docs.swaps.xyz/guides/token-approvals
Check for approvals and broadcast both the approval and Swaps transaction in a single call.
## Batch token approvals with Swaps transactions
On EVM chains, you will need to grant token approvals to submit transactions. The `spender` in the approval should be the `to` address in the transaction object returned by the `/getAction` endpoint.
Recent EIPs enable applications to batch the approval and Swaps transactions. This means EVM ERC20 transactions are still only a single transaction for your users.
We recommend the [`wallet_sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls#sendcalls) method enabled by [EIP 5792](https://github.com/ethereum/EIPs/blob/815028dc634463e1716fc5ce44c019a6040f0bef/EIPS/eip-5792.md).
The example below generates a cross-chain swap for 10 USDC on Base to USDT on Arbitrum. It demonstrates how to call the `/getAction` endpoint and batch the returned transaction with an approval for 10 USDC on Base so that both the approval and swap can be submitted in a single transaction. Refer to the \[EVM Broadcast Guide]
```typescript sendBatchedTx.ts theme={null}
import { getAction } from "./getAction";
import { parseAbiItem } from "viem";
import { walletClient } from "./config";
const actionRequest: ActionRequest = {
actionType: "swap-action",
sender: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // generally the user's connected wallet address
srcToken: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // USDC on Base
dstToken: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", // USDT on Arbitrum
srcChainId: 8453, // Base Chain ID
dstChainId: 42161, // Arbitrum Chain ID
slippage: 100, // bps
swapDirection: "exact-amount-in",
amount: 10000000n, // denominated in srcToken decimals
recipient: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
};
const tx = await getAction({ actionRequest });
export async function sendBatchedTx() {
const { id } = await walletClient.sendCalls([
calls: [
{
to: actionRequest.srcToken,
abi: parseAbiItem('function approve(address, uint256) returns (bool)'),
functionName: 'approve',
args: [
tx.to,
amount
]
},
{
to: tx.to,
value: tx.value,
data: tx.data
},
]
]);
return id;
}
```
```typescript getAction.ts theme={null}
import { sendTransaction } from "@wagmi/core";
import { useAccount } from "wagmi";
async function getAction({ actionRequest }): Promise {
const url = new URL("https://api-v2.swaps.xyz/api/getAction");
Object.entries(actionRequest).forEach(([key, value]) => {
url.searchParams.set(key, String(value));
});
const requestOptions = {
method: "GET",
headers: { "x-api-key": SWAPS_API_KEY },
};
const response = await fetch(url.toString(), requestOptions);
const { tx } = await response.json();
return tx;
}
```
Alternatively, you like to use [EIP-7702](https://viem.sh/docs/eip7702), which enables EOAs to designate a smart contract as its implementation. This EIP equips EOAs with features previously reserved for smart contract accounts like transaction batching, sponsorship, and delegated signing. We find EIP 5792 to be a lighter-weight implementation for batching transactions specifically.
For a basic example of the sequenced, legacy approval method, please visit [this NFT mint button example](https://github.com/decentxyz/launch-nfts/blob/c2a5d7300dfe9265a42c7f3e5863606805d65039/components/MintButton.tsx#L32).
# Track Transactions
Source: https://docs.swaps.xyz/guides/track-transactions
Monitor the status of transactions and trigger indexing for alt VM transactions.
Swaps provides a status endpoint you can use to track your transactions. The endpoint provides status updates and key transaction data for any transaction type. Key transaction data includes the USD value of the transaction, transaction fees, execution path, and other useful on-chain information.
For transactions originating on alt VMs (e.g., Bitcoin, Ripple), you will need to register your transaction by submitting a `POST` request containing the transaction's `txHash`.
## Get status
**API Reference:** [Get Status](/swap-api-reference/get-status)
The status endpoint supports three query parameters:
| Parameter | Description |
| :-------- | :------------------------------------------------------------------ |
| `chainId` | Source chain ID of the transaction |
| `txHash` | Source or destination transaction hash |
| `txId` | Unique identifier applied to each transaction by the Swaps protocol |
We recommend using the source chain ID and the transaction hash. The example below assumes this approach.
The status endpoint will return a [`TxDetails` object](/swap-api-reference/get-status#response-status-message).
```typescript theme={null}
async function getStatus(
srcChainId: ChainId,
srcTxHash: string
): Promise {
const url = `https://ghost.swaps.xyz/api/v2/getStatus?chainId=${srcChainId}&txHash=${srcTxHash}`;
const options = {
method: "GET",
headers: { "x-api-key": SWAPS_API_KEY },
};
const response = await fetch(url, options);
const txDetails = await response.json();
}
```
**If you would prefer to use webhooks, please reference the [webhook
documentation](/guides/track-transactions#webhooks) below.**
## Register transaction
**API Reference:** [Register Transaction](/swap-api-reference/register-transaction)
Registering a transaction triggers indexing after it is broadcasted on the source chain.
This is required for any transactions that return an `alt-vm-*` bridge ID in the [Action Response](/swap-api-reference/get-action). The Action Response also includes a `requiresRegisterTx` flag. This is covered in the [alt VM broadcast guide](/guides/swap#broadcast-on-altvm). Swaps will automatically register any transaction submitted to a named VM. If you believe we have missed a transaction, calling the register transaction endpoint will trigger indexing.
This endpoint does support registering multiple transactions in a single call.
| Parameter | Description |
| :-------- | :----------------------------------------------- |
| `txId` | The **transaction ID** from the action response. |
| `txHash` | The **transaction hash** from the source chain. |
```typescript theme={null}
async function registerTx(
txId: string,
srcTxHash: string
): Promise<{ success: true; error: string | null }> {
const url = "https://api-v2.swaps.xyz/api/registerTxs";
const options = {
method: "POST",
headers: {
"x-api-key": SWAPS_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
txId,
txHash: srcTxHash
}),
};
const response = await fetch(url, options);
const data = await response.json();
}
```
## Webhooks
Swaps can emit webhooks on transaction creation and completion (success or failure) events. To use webhooks, please register a webhook URL in the developer console. Webhook URLs should correspond to a certain API key -- each API key represents a unique `appId`. Each `appId` can have its own webhook URL.
🚧 The Console does not yet support webhook URL registration. 🚧 Please
contact the Swaps team to register a URL.
Swaps' webhooks are sent with a `x-signature-256` header that hashes the raw request body and delivery timestamp. This signature ensures that neither the request body nor the timestamp were modified and can be trusted as sent from Swaps.
The webhook body mirrors the [`TxDetails` object](/swap-api-reference/get-status#response-status-message) returned from the `/getStatus` endpoint. The schema is:
```typescript theme={null}
type WebhookBody = {
event: "created" | "updated"; // "updated" is emitted on tx completion
txStatus: StatusDetails;
timestamp: number;
};
```
To verify the webhook signature, hash the payload with your webhook secret using SHA256 and confirm that the timestamp is within an expected buffer. Please see a reference implementation below:
```typescript theme={null}
function verifyWebhook(payload, signature, secret) {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
const receivedSignature = signature.replace("sha256=", "");
// Use constant-time comparison
const sigBuffer = Buffer.from(receivedSignature, "hex");
const expectedBuffer = Buffer.from(expectedSignature, "hex");
if (sigBuffer.length !== expectedBuffer.length) {
return false;
}
return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}
// Sample usage in Express handler
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-signature-256"];
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
// Process webhook...
res.status(200).send("OK");
});
```
# Introduction
Source: https://docs.swaps.xyz/index
Swaps offers flexible APIs for lightning-fast swaps, bridging, and cross-chain calls.
Swaps is the execution layer for moving value across chains: swaps, bridges, cross-chain contract calls, prediction market trading, and dedicated stableswap liquidity — behind one API. Your users transact with **any token on any chain**; Swaps handles routing, transaction construction, and end-to-end tracking.
## What you can build
One `getAction` call returns a ready-to-broadcast transaction for any swap, bridge, or cross-chain contract call.
Let users bet on Polymarket with whatever they hold — one call from any token on any chain to a placed order.
Stable-pair pricing far tighter than general-purpose AMMs, routed automatically inside `getAction`.
DEX aggregator or solver? Route over Swaps' stableswap liquidity directly at the contract level.
## Send Your First Transaction
Here you’ll find an interactive API playground and detailed integration guides to help you seamlessly send your first swap, bridge, or cross-chain call transaction.
To get started, check out our:
Follow our guide for step-by-step walkthrough of integration recommendations.
or test each step of the flow yourself!
Get available paths for a given source token.
Call the `/getAction` endpoint to return a serialized swap or cross-chain-call
transaction.
Reference the broadcast methods in the Swap Guide for each VM.
For [Alt VMs](/resources/best-practices#pay-attention-to-named-vs-alt-vms),
register your transaction to trigger indexing.
Leverage the status endpoint or webhooks to track end-to-end execution.
Return all transactions for your org.
## Integrate Prediction Markets
Swaps enables users to seamlessly trade on prediction markets directly from their wallet using any token on any chain.
Compare the one-call chain-abstracted flow against the direct three-step flow and pick the right fit for your app.
Try out our reference application to see how we've abstracted prediction market trading to a single swap!
Check out the discovery path and network requests to quickly add prediction markets to your app.
# Create or Fetch User
Source: https://docs.swaps.xyz/prediction-market-reference/create-or-fetch-user
/prediction-market-reference/openapi.json post /api/workflows/polymarket/createOrFetchPolymarketUser
Creates a new Swaps account for a user or fetches an existing one based on the provided EVM address.
# Get Activity
Source: https://docs.swaps.xyz/prediction-market-reference/get-activity
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getActivity
Retrieve comprehensive activity history for a specific user, including orders, trades, and other actions.
# Get Closed Positions
Source: https://docs.swaps.xyz/prediction-market-reference/get-closed-positions
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getClosedPositions
Retrieve closed positions (resolved markets) for a specific user.
# Get Current Positions
Source: https://docs.swaps.xyz/prediction-market-reference/get-current-positions
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getCurrentPositions
Retrieve all current open positions for a specific user.
# Get Event
Source: https://docs.swaps.xyz/prediction-market-reference/get-event
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getEvent
Retrieve detailed information about a specific event, including all associated markets.
# Get Market Price
Source: https://docs.swaps.xyz/prediction-market-reference/get-market-price
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getMarketPrice
Retrieve the current best price for a specific token and side (BUY or SELL).
# Get Markets
Source: https://docs.swaps.xyz/prediction-market-reference/get-markets
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getMarkets
Retrieve market information by CLOB token IDs, slugs, or tag ID.
# Get Price History
Source: https://docs.swaps.xyz/prediction-market-reference/get-price-history
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getPriceHistory
Retrieve historical price data for a specific token over a given time interval.
# Get Profit and Loss
Source: https://docs.swaps.xyz/prediction-market-reference/get-profit-and-loss
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getPnL
Retrieve aggregate profit and loss information across all positions for a specific user.
# Get Tags
Source: https://docs.swaps.xyz/prediction-market-reference/get-tags
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getTags
Retrieve all available tags for filtering markets.
# Get Trades
Source: https://docs.swaps.xyz/prediction-market-reference/get-trades
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getTrades
Retrieve trade history for a specific user.
# Get Trending Markets
Source: https://docs.swaps.xyz/prediction-market-reference/get-trending-markets
/prediction-market-reference/openapi.json get /api/workflows/polymarket/getTrendingMarkets
Retrieve trending markets sorted by 24-hour volume. Markets must have minimum $150K of 24h volume.
# Get Workflow Status
Source: https://docs.swaps.xyz/prediction-market-reference/get-workflow-status
/prediction-market-reference/openapi.json get /api/workflows/getStatus
Retrieves the status of a workflow transaction by transaction ID.
# Integration Patterns
Source: https://docs.swaps.xyz/prediction-market-reference/integration-patterns
Two ways to integrate Polymarket trading: one chain-abstracted getAction call, or the direct three-step flow.
Swaps supports two integration patterns for placing prediction market orders.
The **chain-abstracted** pattern is the core value proposition: users transact
on Polymarket with **any token on any chain, directly from their existing
wallet** — instead of needing a Polymarket trading account and pUSD. The
**direct** pattern trades that simplicity for control over funding and order
timing.
Both settle on the same rails: the user's deposit (proxy) wallet on Polygon
and the Polymarket CLOB.
| | Chain abstracted | Direct |
| ----------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| Calls to place an order | 1 (`getAction`) | 3 (`createOrFetchPolymarketUser` → fund → `placeOrder`) |
| Source of funds | Any token on any chain, per order | Pre-funded deposit wallet (collateral on Polygon) |
| EIP-712 signature | Not required to place | Required on every trading call — see the [signing guide](/prediction-market-reference/polymarket-signing) |
| Order latency | Swap + order (cross-chain settlement time) | Order only — immediate against the CLOB |
| Best for | "Let users bet with whatever they hold" | Trading UIs with balances, repeat orders, tighter control |
## Pattern 1 — Chain abstracted (one call)
One `getAction` request with `actionType=polymarket` swaps any token on any
chain into collateral and places the order when funds arrive. The only setup
is a one-time `createOrFetchPolymarketUser` call your app makes behind the
scenes to provision the user's deposit wallet. Full parameter reference:
[Place Order (Chain Abstracted)](/prediction-market-reference/place-order-chain-abstracted).
```mermaid theme={null}
sequenceDiagram
participant User
participant App as Your App
participant Swaps as Swaps API
participant CLOB as Polymarket CLOB
Note over App,Swaps: one-time setup per user
App->>Swaps: POST /createOrFetchPolymarketUser (evmEoa)
Swaps-->>App: userId + deposit wallet
Note over App,Swaps: per order
App->>Swaps: GET /getAction (actionType=polymarket, userId)
Swaps-->>App: transaction + txId
User->>User: sign & broadcast transaction
Note over Swaps: swap settles, collateral lands in deposit wallet
Swaps->>CLOB: place order
App->>Swaps: GET /workflows/getStatus?txId=...
Swaps-->>App: workflow status + order result
```
## Pattern 2 — Direct (three steps)
The direct flow separates account setup, funding, and ordering. Once the
deposit wallet is funded, orders execute immediately against the CLOB with no
swap in the critical path.
### Step 1 — Deploy the deposit wallet
Call [`POST /createOrFetchPolymarketUser`](/prediction-market-reference/create-or-fetch-user)
with the user's `evmEoa`. It returns the `userId` and a deposit (proxy) wallet
keyed to that EOA, deploying one if it doesn't exist yet.
Check `proxyWalletStatus` before trading:
| Status | Meaning |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| `ready` | Wallet is deployed and tradeable. |
| `deploying` / `permissioning` | Setup in progress — poll until `ready`. |
| `failed-deploy` / `failed-permission` | Setup failed — retry the call. |
| `temporary-frozen` | Wallet is frozen — call the endpoint again with `unfreeze: true` in the body. |
| `not-created` | No wallet yet — the call will create one. |
### Step 2 — Fund the deposit wallet
Fund the wallet with Polymarket collateral — **pUSD on Polygon**
(`0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB`, chain `137`). From any other
token or chain, use a standard [`getAction` swap](/swap-api-reference/get-action)
with the deposit wallet as the `recipient`:
```bash theme={null}
curl "https://api-v2.swaps.xyz/api/getAction?\
actionType=swap-action&\
sender=0xB9519a08267d7B259eCA6DbD8F7286B1f176A41f&\
srcChainId=8453&\
srcToken=0x0000000000000000000000000000000000000000&\
dstChainId=137&\
dstToken=0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB&\
amount=10000000000000000&\
swapDirection=exact-amount-in&\
slippage=100&\
recipient=" \
-H "x-api-key: $API_KEY"
```
### Step 3 — Place the order
Call [`POST /placeOrder`](/prediction-market-reference/place-order) with the
order details and an EIP-712 `signatureByEvmEoa` produced by the user's EOA —
Swaps verifies the signature and relays the order to the Polymarket CLOB. See
the [Polymarket Signing Guide](/prediction-market-reference/polymarket-signing)
for the typed-data schema and a working example.
```mermaid theme={null}
sequenceDiagram
participant User
participant App as Your App
participant Swaps as Swaps API
participant CLOB as Polymarket CLOB
App->>Swaps: POST /createOrFetchPolymarketUser (evmEoa)
Swaps-->>App: userId + deposit wallet (proxyWalletStatus)
App->>Swaps: GET /getAction (swap to pUSD on Polygon, recipient = deposit wallet)
User->>User: sign & broadcast funding transaction
Note over Swaps: collateral lands in deposit wallet
User->>User: sign PlaceOrder typed data (EIP-712)
App->>Swaps: POST /placeOrder (signatureByEvmEoa)
Swaps->>CLOB: relay order
Swaps-->>App: txId + orderResponse
```
## After the order
Both patterns converge on the same lifecycle: track execution with
[`GET /workflows/getStatus`](/prediction-market-reference/get-workflow-status),
then manage positions with sell, redeem, merge, and withdraw. See the
[Transaction Lifecycle](/prediction-market-reference/transaction-lifecycle)
for the end-to-end walkthrough.
# Merge Position
Source: https://docs.swaps.xyz/prediction-market-reference/merge-position
/prediction-market-reference/openapi.json post /api/workflows/polymarket/mergePositions
Merges a full set of position tokens back into collateral by burning them. Can be used to claim winnings from resolved markets or clean up positions. Endpoint awaits successful execution of the merge transaction before returning the transaction hash.
# Overview
Source: https://docs.swaps.xyz/prediction-market-reference/overview
Trade on prediction markets and query market data, user positions, and trading activity.
Swaps enables users to trade on [Polymarket](https://polymarket.com) using **any token on any chain, directly from their existing wallet** — instead of needing a Polymarket trading account and pUSD. This reference covers the full lifecycle: discovering markets, placing orders, tracking workflows, managing positions, and withdrawing funds.
**Why build prediction markets on Swaps:**
* **One call to place a bet.** A single `getAction` request swaps any token on any chain into collateral and places the order — the fastest path from "user holds ETH on Base" to "position on Polymarket".
* **The full stack in one API.** Market discovery, live prices, order placement, position management, PnL, and withdrawals — no stitching together separate data and execution providers.
* **Non-custodial by design.** Every user gets a deposit wallet keyed to their own EOA, and every trading call is authorized by the user's EIP-712 signature.
New to the integration? Start with the [Integration Patterns](/prediction-market-reference/integration-patterns) guide — it compares the one-call chain-abstracted flow against the direct three-step flow — then follow the [Transaction Lifecycle](/prediction-market-reference/transaction-lifecycle) walkthrough.
## Endpoint reference
### Trading
| API | Description |
| :------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------- |
| [Place Order (Chain Abstracted)](/prediction-market-reference/place-order-chain-abstracted) | Place an order with a single `getAction` call using any token on any chain, from the user's existing wallet |
| [Create or Fetch User](/prediction-market-reference/create-or-fetch-user) | Deploy or fetch the user's deposit (proxy) wallet |
| [Place Order](/prediction-market-reference/place-order) | Place a signed order directly against the Polymarket CLOB |
| [Sell Position](/prediction-market-reference/sell-position) | Exit a position with a market order |
| [Redeem Position](/prediction-market-reference/redeem-position) | Claim winnings from a resolved market |
| [Merge Position](/prediction-market-reference/merge-position) | Combine complementary YES/NO holdings back into collateral |
| [Withdraw](/prediction-market-reference/withdraw) | Withdraw collateral to any wallet, token, or chain |
| [Get Workflow Status](/prediction-market-reference/get-workflow-status) | Track the status of a workflow execution |
### Market Discovery
| API | Description |
| :------------------------------------------------------------------------ | :----------------------------------------------------------- |
| [Search Markets](/prediction-market-reference/search-markets) | Query markets by keywords or tags |
| [Get Trending Markets](/prediction-market-reference/get-trending-markets) | Discover high-volume markets sorted by 24hr trading activity |
| [Get Tags](/prediction-market-reference/get-tags) | Retrieve categories for filtering markets |
### Market Information
| API | Description |
| :------------------------------------------------------------------ | :------------------------------------------------------------ |
| [Get Event](/prediction-market-reference/get-event) | Retrieve complete event details with all associated markets |
| [Get Markets](/prediction-market-reference/get-markets) | Query specific markets by token ID, slug, or category |
| [Get Market Price](/prediction-market-reference/get-market-price) | Fetch current best bid/ask prices |
| [Get Price History](/prediction-market-reference/get-price-history) | Analyze historical price data across different time intervals |
### User Positions & Activity
| API | Description |
| :-------------------------------------------------------------------------- | :------------------------------------------------------ |
| [Get Current Positions](/prediction-market-reference/get-current-positions) | View all open positions with PnL calculations |
| [Get Closed Positions](/prediction-market-reference/get-closed-positions) | Access historical positions from resolved markets |
| [Get Trades](/prediction-market-reference/get-trades) | Retrieve detailed trade history |
| [Get Activity](/prediction-market-reference/get-activity) | Comprehensive activity feed including orders and trades |
| [Get PnL](/prediction-market-reference/get-profit-and-loss) | Aggregate profit and loss summary |
## Authentication
All API endpoints require authentication using API keys passed via the `x-api-key` header. We have provided a highly ratelimited API key for testing in the API playground.
Create a key in the [Console](https://console.swaps.xyz).
## Getting Started
1. **Discover Markets**: Start with the search or trending endpoints to find markets
2. **Place Orders**: Pick an [integration pattern](/prediction-market-reference/integration-patterns) and place your first order
3. **Track Workflows**: Follow execution with [Get Workflow Status](/prediction-market-reference/get-workflow-status)
4. **Manage Positions**: Sell, redeem, or merge positions and withdraw collateral
In accordance with the underlying prediction markets, Swaps' prediction market APIs are not available to users located in the United States.
## Related Resources
* [Polymarket Demo App](https://box-monorepo-example-app.vercel.app/testApiPolymarket) - Test Swaps' prediction market APIs by sending live Polymarket orders. Provides a reference for the discovery path and network requests to quickly add prediction markets to your app.
# Place Order
Source: https://docs.swaps.xyz/prediction-market-reference/place-order
/prediction-market-reference/openapi.json post /api/workflows/polymarket/placeOrder
Places a market order (BUY or SELL) directly against the Polymarket CLOB on behalf of the user, using their pre-funded proxy wallet.
This endpoint always requires an EIP-712 `signatureByEvmEoa` produced by the user's EOA — see the [Polymarket Signing Guide](/prediction-market-reference/polymarket-signing). The endpoint submits the order synchronously and returns `{ txId, orderResponse }` so callers can poll workflow status.
# Place Order (Chain Abstracted)
Source: https://docs.swaps.xyz/prediction-market-reference/place-order-chain-abstracted
Place a Polymarket order with a single getAction call — any token, any chain, straight from the user's existing wallet.
The chain-abstracted flow lets users transact on Polymarket with **any token
on any chain, directly from the wallet they already have** — no Polymarket
trading account to set up and no pUSD to acquire. One call to
[`GET /getAction`](/swap-api-reference/get-action) with `actionType=polymarket`
returns a transaction that swaps the user's token into Polymarket collateral
and places the order once funds arrive. No separate funding step and no
EIP-712 signature are required.
This page documents the `polymarket` variant of `getAction`. The canonical
endpoint reference — including all base parameters and the full response schema
— lives in the [Swap API Reference](/swap-api-reference/get-action).
## Prerequisites
* A `userId` for the trader's EOA. Call
[`POST /createOrFetchPolymarketUser`](/prediction-market-reference/create-or-fetch-user)
once from your app: it returns the `userId` and a deposit (proxy) wallet
keyed to the user's EOA, which you pass as `recipient`. This is a single
API call your app makes behind the scenes — the user never signs up for
anything.
* A market to trade. Use the
[market discovery endpoints](/prediction-market-reference/search-markets) to
find the CLOB `tokenID`, `tickSize`, and `negRisk` for the outcome you want.
## Request
`GET /getAction` with the standard base parameters (`sender`, `srcChainId`,
`srcToken`, `dstChainId`, `dstToken`, `slippage`) plus:
| Parameter | Required | Description |
| --------------- | -------- | ----------------------------------------------------------------------- |
| `actionType` | Yes | Must be `polymarket`. |
| `userId` | Yes | Polymarket user ID returned by `createOrFetchPolymarketUser`. |
| `side` | Yes | `BUY` or `SELL`. |
| `tokenID` | Yes | Polymarket CLOB token ID of the outcome to trade. |
| `orderType` | Yes | `FOK` (Fill-Or-Kill) or `FAK` (Fill-And-Kill) — market orders. |
| `tickSize` | Yes | Price tick size from the market details (`0.01`, `0.001`, or `0.0001`). |
| `negRisk` | Yes | Negative-risk flag from the market details (`true` or `false`). |
| `amount` | Yes | Exact-in amount of the source token (base units). |
| `swapDirection` | No | Defaults to `exact-amount-in` (recommended). |
| `recipient` | Yes | The user's deposit (proxy) wallet address. |
The source token can be **any token on any supported chain** — Swaps routes it
into Polymarket collateral on Polygon as part of the action.
### Example
```bash theme={null}
curl "https://api-v2.swaps.xyz/api/getAction?\
actionType=polymarket&\
sender=0xB9519a08267d7B259eCA6DbD8F7286B1f176A41f&\
srcChainId=8453&\
srcToken=0x0000000000000000000000000000000000000000&\
dstChainId=137&\
dstToken=0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB&\
amount=10000000000000000&\
swapDirection=exact-amount-in&\
slippage=100&\
recipient=0x0797bfec6d2d4f733d461bbee8125805e9e9c892&\
userId=0x0797bfec6d2d4f733d461bbee8125805e9e9c892&\
side=BUY&\
tokenID=90234889617199443673709150877675264662915065327694355570468014972602766235849&\
orderType=FOK&\
tickSize=0.01&\
negRisk=true" \
-H "x-api-key: $API_KEY"
```
This example spends 0.01 ETH on Base to buy an outcome token; the destination
is Polymarket collateral on Polygon (`137`) delivered to the user's deposit
wallet.
## Minimum order size
For `BUY` orders (`FOK`/`FAK`), the collateral amount that would arrive after
the swap (`amountOutMin`) is validated before a transaction is returned:
1. Orders below **\$1** are always rejected.
2. The amount must also clear the market's own minimum order size on the
Polymarket CLOB.
Requests that fail validation return a getAction error response indicating the
amount is too low, the market is unavailable, or the price moved out of range —
raise the input amount or refresh the quote and retry.
## Response and tracking
The response is a standard getAction
[`ActionResponse`](/swap-api-reference/get-action): a transaction to sign and
broadcast, quoted amounts, and a `txId`.
After the user broadcasts the transaction, Swaps completes the swap, delivers
collateral to the deposit wallet, and places the order on the CLOB. Track
end-to-end progress with
[`GET /workflows/getStatus`](/prediction-market-reference/get-workflow-status)
using the `txId`.
## When to use this pattern
Use the chain-abstracted flow whenever the user's funds start outside the
deposit wallet — it turns "hold ETH on Base, bet on Polymarket" into one
signature. See
[Integration Patterns](/prediction-market-reference/integration-patterns) for
a comparison with the direct (three-step) flow, which offers more control in
exchange for explicit funding and EIP-712 signing.
# Polymarket Signing Guide
Source: https://docs.swaps.xyz/prediction-market-reference/polymarket-signing
How to produce the `signatureByEvmEoa` EIP-712 signature for Polymarket workflow endpoints.
Every Polymarket trading endpoint requires a `signatureByEvmEoa` field — an
EIP-712 signature produced by the user's home EOA that authorizes the request.
This page describes the typed-data schemas, the signing flow, and a working
viem example.
## Signature requirements
`signatureByEvmEoa` + `expiration` are **required on every request** to:
| Endpoint | What the signature authorizes |
| ------------------------------------------- | --------------------------------------------- |
| `POST /workflows/polymarket/placeOrder` | The order parameters. |
| `POST /workflows/polymarket/sellPosition` | The sale parameters and proceeds destination. |
| `POST /workflows/polymarket/redeemPosition` | The redemption and proceeds destination. |
| `POST /workflows/polymarket/withdraw` | The withdrawal destination. |
## Expiration window
`expiration` is a Unix timestamp in **seconds**. The backend rejects:
* expirations in the past,
* expirations more than **300 seconds** (5 minutes) in the future,
* non-integer or non-finite values.
Compute it close to send time, e.g. `Math.floor(Date.now() / 1000) + 60`.
## Typed-data schemas
All three schemas use the same EIP-712 domain shape — `version: '1'`,
`chainId: 137` (Polygon). Only the domain `name` and the `primaryType` change.
Address- and chainId-shaped fields are signed as `string` so absent optionals
can be represented as the empty string `""`. When an optional is omitted from
the request body, sign it as `""` (not `"0x0000..."` or `"0"`).
### `PlaceOrder` — used by `placeOrder`
```ts theme={null}
const domain = {
name: 'BoxPolymarketPlaceOrder',
version: '1',
chainId: 137,
};
const types = {
PlaceOrder: [
{ name: 'tokenID', type: 'string' },
{ name: 'side', type: 'string' },
{ name: 'orderType', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'tickSize', type: 'string' },
{ name: 'negRisk', type: 'bool' },
{ name: 'slippage', type: 'uint256' },
{ name: 'expiration', type: 'uint256' },
],
};
```
### `RedeemPosition` — used by `redeemPosition`
```ts theme={null}
const domain = {
name: 'BoxPolymarketRedeemPosition',
version: '1',
chainId: 137,
};
const types = {
RedeemPosition: [
{ name: 'conditionId', type: 'string' },
{ name: 'assetId', type: 'string' },
{ name: 'dstTokenAddress', type: 'string' },
{ name: 'dstTokenChainId', type: 'string' },
{ name: 'dstWalletAddress', type: 'string' },
{ name: 'expiration', type: 'uint256' },
],
};
```
### `SellPosition` — used by `sellPosition`
```ts theme={null}
const domain = {
name: 'BoxPolymarketSellPosition',
version: '1',
chainId: 137,
};
const types = {
SellPosition: [
{ name: 'proxyWallet', type: 'string' },
{ name: 'tokenID', type: 'string' },
{ name: 'side', type: 'string' },
{ name: 'orderType', type: 'string' },
{ name: 'tickSize', type: 'string' },
{ name: 'negRisk', type: 'bool' },
{ name: 'amount', type: 'uint256' },
{ name: 'slippage', type: 'uint256' },
{ name: 'dstTokenAddress', type: 'string' },
{ name: 'dstTokenChainId', type: 'string' },
{ name: 'dstWalletAddress', type: 'string' },
{ name: 'expiration', type: 'uint256' },
],
};
```
### `Withdraw` — used by `withdraw`
```ts theme={null}
const domain = {
name: 'BoxPolymarketWithdraw',
version: '1',
chainId: 137,
};
const types = {
Withdraw: [
{ name: 'srcTokenAddress', type: 'string' },
{ name: 'dstTokenAddress', type: 'string' },
{ name: 'dstTokenChainId', type: 'string' },
{ name: 'dstWalletAddress', type: 'string' },
{ name: 'expiration', type: 'uint256' },
],
};
```
`srcTokenAddress` selects which token to withdraw from the proxy wallet (defaults to
pUSD collateral when omitted). It is always on Polygon, so only the address is signed —
there is no `srcTokenChainId`. `dstToken` selects the token delivered to
`dstWalletAddress`.
## Building the message
A few field-specific rules apply when assembling the `message` object:
* **Amount scaling.** For `PlaceOrder` and `SellPosition`, `amount` is the USD
amount scaled to 6 decimals: `BigInt(Math.floor(amount * 1_000_000))`. The
request body still carries the un-scaled number (e.g. `2.5`); the scaling
applies only to the signed value.
* **uint256 fields.** `slippage` and `expiration` must be `bigint` when signing
(`BigInt(slippage)`, `BigInt(expiration)`).
* **Empty-string optionals.** Map omitted optionals to `""`:
* `srcTokenAddress` absent (withdraw) → `srcTokenAddress: ""`.
* `dstToken` absent → `dstTokenAddress: ""`, `dstTokenChainId: ""`.
* `proxyWallet` absent (sell) → `proxyWallet: ""`.
* **Chain ID as string.** When `dstToken` is present, sign
`dstTokenChainId: String(dstToken.chainId)`.
## Example — sign and submit a `placeOrder`
```ts theme={null}
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(privateKey);
const orderRequest = {
side: 'BUY',
tokenID: '902348896171994436737091508776752646...',
orderType: 'FOK',
amount: 2,
tickSize: '0.01',
negRisk: true,
slippage: 100,
};
const expiration = Math.floor(Date.now() / 1000) + 60; // 60s in the future
const signatureByEvmEoa = await account.signTypedData({
domain: {
name: 'BoxPolymarketPlaceOrder',
version: '1',
chainId: 137,
},
types: {
PlaceOrder: [
{ name: 'tokenID', type: 'string' },
{ name: 'side', type: 'string' },
{ name: 'orderType', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'tickSize', type: 'string' },
{ name: 'negRisk', type: 'bool' },
{ name: 'slippage', type: 'uint256' },
{ name: 'expiration', type: 'uint256' },
],
},
primaryType: 'PlaceOrder',
message: {
tokenID: orderRequest.tokenID,
side: orderRequest.side,
orderType: orderRequest.orderType,
amount: BigInt(Math.floor(orderRequest.amount * 1_000_000)),
tickSize: orderRequest.tickSize,
negRisk: orderRequest.negRisk,
slippage: BigInt(orderRequest.slippage),
expiration: BigInt(expiration),
},
});
await fetch('https://api-v2.swaps.xyz/api/workflows/polymarket/placeOrder', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY,
},
body: JSON.stringify({
evmEoa: account.address,
orderRequest,
expiration,
signatureByEvmEoa,
}),
});
```
The same pattern applies to `redeemPosition` and `sellPosition` — swap the
domain `name`, `primaryType`, and `types` for the matching schema and include
the additional `dstTokenAddress`, `dstTokenChainId`, and `dstWalletAddress`
fields (using `""` when their request-body counterpart is omitted).
# Redeem Position
Source: https://docs.swaps.xyz/prediction-market-reference/redeem-position
/prediction-market-reference/openapi.json post /api/workflows/polymarket/redeemPosition
Redeems position from a resolved Polymarket market. For positions with a current value > 0, this endpoint allows users to claim their winnings from a specific market condition. For losing positions with a current value = 0, this endpoint allows users to burn their position tokens to clean up their account.
Endpoint awaits successful execution of the redemption transaction before returning the transaction hash.
Every request must include `expiration` and an EIP-712 `signatureByEvmEoa` over the `RedeemPosition` typed data — see the [Polymarket Signing Guide](/prediction-market-reference/polymarket-signing).
Proceeds default to the caller's `evmEoa`. To deliver them to a different wallet or token, set `dstWalletAddress` and/or `dstToken`.
# Search Markets
Source: https://docs.swaps.xyz/prediction-market-reference/search-markets
/prediction-market-reference/openapi.json get /api/workflows/polymarket/search
Search for markets and events by query string or tags.
# Sell Position
Source: https://docs.swaps.xyz/prediction-market-reference/sell-position
/prediction-market-reference/openapi.json post /api/workflows/polymarket/sellPosition
Sells an existing position in a Polymarket market. This endpoint allows users to exit their positions by selling their outcome tokens using market orders (FOK/FAK).
Every request must include `expiration` and an EIP-712 `signatureByEvmEoa` over the `SellPosition` typed data — see the [Polymarket Signing Guide](/prediction-market-reference/polymarket-signing).
Proceeds default to the caller's `evmEoa`. To deliver them to a different wallet or token, set `dstWalletAddress` and/or `dstToken`.
# Transaction Lifecycle
Source: https://docs.swaps.xyz/prediction-market-reference/transaction-lifecycle
End-to-end walkthrough: discover a market, place an order, track it, manage the position, and withdraw.
This page walks through the full life of a prediction market position on
Swaps, from market discovery to withdrawal.
```mermaid theme={null}
flowchart LR
discover["Discover market"] --> place["Place order"]
place --> track["Track workflow"]
track --> manage["Sell / Redeem / Merge"]
manage --> withdrawStep["Withdraw"]
```
## 1. Discover a market
Find markets and the details needed to trade them:
* [`Search Markets`](/prediction-market-reference/search-markets) — query by
keywords or tags.
* [`Get Trending Markets`](/prediction-market-reference/get-trending-markets) —
high-volume markets by 24h activity.
* [`Get Markets`](/prediction-market-reference/get-markets) /
[`Get Event`](/prediction-market-reference/get-event) — full market details.
From the market details, capture the CLOB `tokenID` of the outcome, the
`tickSize`, and the `negRisk` flag — every order needs them. Use
[`Get Market Price`](/prediction-market-reference/get-market-price) for
current bid/ask.
## 2. Place an order
Choose an [integration pattern](/prediction-market-reference/integration-patterns):
* **Chain abstracted** — one
[`getAction` call](/prediction-market-reference/place-order-chain-abstracted)
that swaps any token on any chain from the user's existing wallet and
places the order.
* **Direct** —
[`createOrFetchPolymarketUser`](/prediction-market-reference/create-or-fetch-user),
fund the deposit wallet with pUSD on Polygon, then
[`placeOrder`](/prediction-market-reference/place-order) with an EIP-712
signature ([signing guide](/prediction-market-reference/polymarket-signing)).
## 3. Track the workflow
Every order returns a `txId`. Poll
[`GET /workflows/getStatus`](/prediction-market-reference/get-workflow-status)
with it to follow execution — the response reports the workflow `status`
(`pending`, `success`, `failed`), the `operation` (e.g. `placeOrder`), and
operation data including the order result.
Monitor open positions with
[`Get Current Positions`](/prediction-market-reference/get-current-positions)
and activity with [`Get Activity`](/prediction-market-reference/get-activity).
## 4. Manage the position
* [`Sell Position`](/prediction-market-reference/sell-position) — exit before
resolution with a market order (FOK/FAK).
* [`Redeem Position`](/prediction-market-reference/redeem-position) — claim
winnings from a resolved market (or burn worthless outcome tokens).
* [`Merge Position`](/prediction-market-reference/merge-position) — combine
complementary YES/NO holdings back into collateral.
Every sell and redeem request is signed with EIP-712 — see the
[signing guide](/prediction-market-reference/polymarket-signing). Proceeds
default to the caller's EOA; set `dstWalletAddress` and/or `dstToken` to
deliver them anywhere else.
## 5. Withdraw
Move collateral out of the deposit wallet with
[`Withdraw`](/prediction-market-reference/withdraw) — funds go to any wallet,
optionally swapped into a different token or chain, authorized by an EIP-712
signature.
Withdrawals are workflows too — track them with the same
[`GET /workflows/getStatus`](/prediction-market-reference/get-workflow-status)
endpoint.
# Withdraw
Source: https://docs.swaps.xyz/prediction-market-reference/withdraw
/prediction-market-reference/openapi.json post /api/workflows/polymarket/withdraw
Withdraws the user's Polymarket proxy-wallet collateral to an arbitrary `dstWalletAddress`. Optional `dstToken` swaps the proxy collateral into a different token (and/or chain) before delivery.
This endpoint **always requires** an EIP-712 `signatureByEvmEoa` produced by the user's EOA over `{ dstToken, dstWalletAddress, expiration }` — see the [Polymarket Signing Guide](/prediction-market-reference/polymarket-signing). The signature is what authorizes funds being sent to a wallet other than the EOA.
The endpoint awaits successful execution of the withdrawal transaction before returning the transaction hash.
# Overview
Source: https://docs.swaps.xyz/protocol-reference/overview
Integrate Swaps' stableswap protocol at the contract level — route over on-chain liquidity directly, without the API.
Swaps runs a dedicated **stableswap protocol**: stable-pair liquidity with
pricing far tighter than general-purpose AMMs, live on **Solana and five EVM
chains**. The Protocol Reference documents how to integrate it at the
**contract level** — no API in the loop.
This integration pattern is ideal for **DEX aggregators, solvers, and routing
infrastructure** that route over on-chain liquidity directly rather than
integrating via APIs: you quote and execute against the contracts yourself,
keep full control of transaction construction, and plug the stableswap venues
into your own routing graph like any other source.
If you want quotes, routing, transaction construction, and tracking handled
for you, use the [Swap API](/swap-api-reference/overview) instead — it routes
through the stableswap protocol automatically (see the
[Stableswaps guide](/guides/stableswaps)).
## Why route over the stableswap venues
* **Tighter stable pricing.** Fees are set per pair, per direction, and
refreshed continuously by an off-chain pricing keeper — not by a static
curve.
* **Gas-free quoting.** Read on-chain fee state (Solana) or call `view` quote
functions (EVM) — quoting costs nothing and slots into any pricing loop.
* **Permissionless at default rates.** No allowlist, no API key — integrate
and route today.
* **Custom pricing for partners.** Negotiated rates are delivered through
Swaps-signed data: an Ed25519 router proof on Solana, per-recipient fee
lookup on EVM. [Reach out to us](https://console.swaps.xyz) to get set up.
* **One protocol, both VMs.** The same liquidity model on Solana and EVM, so
one integration story covers six chains.
## API vs protocol integration
| | Swap API | Stableswap protocol (this reference) |
| ------------------------ | ----------------------------------------------- | ------------------------------------------------------------------ |
| Best for | Apps and wallets | DEX aggregators, solvers, routers |
| Quoting | `getAction` returns a ready transaction | Read on-chain state / call `view` quote functions |
| Routing | Swaps picks the best venue across all liquidity | You route over the stableswap venues directly in your own graph |
| Transaction construction | Done for you | You build and submit |
| Tracking | `getStatus` + webhooks | Your own infrastructure |
| Pricing | Included in the quote | Default rates permissionlessly; custom rates via Swaps-signed data |
## Integrate the venues
The on-chain program: swap instruction, pair-state fees, and router
proofs for custom pricing.
The GhostExchange contract: a quote-and-swap interface over
cross-collateral pools on Ethereum, Arbitrum, Base, Polygon, and Binance.
# Stableswap on EVM
Source: https://docs.swaps.xyz/protocol-reference/stableswap-evm
Integrate the GhostExchange contract directly — quoting, swapping, and pool discovery over cross-collateral stable liquidity.
On EVM, Swaps' stableswap protocol is integrated through the `GhostExchange`
contract — a single-chain swap interface built on paired
CrossCollateralRouter pools, with built-in quoting, slippage protection, and
deadline enforcement. It is designed to slot into a DEX aggregator's routing
graph as a standard quote-and-swap venue.
## Deployments
| Chain | Address |
| -------- | -------------------------------------------- |
| Ethereum | `0xfEAeB7cEFe9f7A42386130af4e1C70a2f0f92F8c` |
| Arbitrum | `0xb9AFF99b40B65C45ab0Fc99146225C05FEd95c3d` |
| Base | `0x369c56802016d699AE7b06b82c0FB98461ff2eF6` |
| Polygon | `0xbE824336888799052d7dc2Cd5Cf18e19d18D77D3` |
| Binance | `0xeCE62f04A5573CE0e30228cD0fB56A8f8e84fcd0` |
Integration is permissionless at **default rates**. The `recipient`
parameter on quotes is used for **fee lookup**: recipients with custom
pricing configured by Swaps quote at their negotiated rates. [Reach out to
us](https://console.swaps.xyz) to arrange custom pricing for your
integration.
## Discover available pairs
Index `PoolAdded` and `PoolRemoved` events to build the set of active pairs:
```solidity theme={null}
event PoolAdded(address indexed tokenA, address indexed tokenB);
event PoolRemoved(address indexed tokenA, address indexed tokenB);
```
To confirm a specific pair on-chain:
```solidity theme={null}
function pools(address tokenA, address tokenB) external view returns (address routerIn, address routerOut);
```
A non-zero return means the pair is tradeable. Pairs are bidirectional.
## Liquidity
The maximum output for a pair is bounded by the target router's token balance:
```solidity theme={null}
(, address routerOut) = ghostExchange.pools(tokenIn, tokenOut);
uint256 maxOutput = IERC20(tokenOut).balanceOf(routerOut);
```
## Quote
Both quote functions are `view` — no gas, no state changes.
```solidity theme={null}
function quoteExactInput(
address tokenIn,
address tokenOut,
uint256 amountIn,
address recipient
) external view returns (uint256 amountOut);
function quoteExactOutput(
address tokenIn,
address tokenOut,
uint256 amountOut,
address recipient
) external view returns (uint256 amountIn);
```
## Swap
The caller must `approve` GhostExchange for `tokenIn` before calling.
```solidity theme={null}
function swapExactInput(
address tokenIn,
address tokenOut,
address recipient, // receives tokenOut
uint256 amountIn,
uint256 amountOutMin, // slippage guard — reverts with TooLittleReceived
uint256 deadline // block.timestamp guard — reverts with DeadlineExpired
) external returns (uint256 amountOut);
function swapExactOutput(
address tokenIn,
address tokenOut,
address recipient, // receives tokenOut
uint256 amountOut,
uint256 amountInMax, // slippage guard — reverts with TooMuchRequested
uint256 deadline
) external returns (uint256 amountIn);
```
## Typical flow
**Exact input** — sell a known amount of `tokenIn`:
```text theme={null}
1. amountOut = GhostExchange.quoteExactInput(tokenIn, tokenOut, amountIn, recipient)
2. IERC20(tokenIn).approve(ghostExchange, amountIn)
3. GhostExchange.swapExactInput(tokenIn, tokenOut, recipient, amountIn, amountOutMin, deadline)
```
**Exact output** — buy a known amount of `tokenOut`:
```text theme={null}
1. amountIn = GhostExchange.quoteExactOutput(tokenIn, tokenOut, amountOut, recipient)
2. IERC20(tokenIn).approve(ghostExchange, amountIn)
3. GhostExchange.swapExactOutput(tokenIn, tokenOut, recipient, amountOut, amountInMax, deadline)
```
## Revert conditions
| Error | Cause |
| ------------------- | -------------------------------------------------------- |
| `PoolDoesNotExist` | No registered pair for tokenIn/tokenOut |
| `AmountTooSmall` | Input too small to produce any output after fees/scaling |
| `TooLittleReceived` | Output \< `amountOutMin` |
| `TooMuchRequested` | Required input > `amountInMax` |
| `DeadlineExpired` | `block.timestamp > deadline` |
## Related
* [Stableswap on Solana](/protocol-reference/stableswap-solana) — the same
protocol as a native Solana program.
* [Stableswaps via the API](/guides/stableswaps) — the same liquidity through
a single `getAction` call.
# Stableswap on Solana
Source: https://docs.swaps.xyz/protocol-reference/stableswap-solana
Integrate the Solana stableswap program directly — swap instruction, pair-state fees, and router proofs for custom pricing.
On Solana, Swaps' stableswap protocol is a single on-chain program, deployed
on mainnet:
```
ghosty4ZU1Qk1HN7Ymz4pZ15QfspzJZgSYFkdKN6ZLK
```
It swaps between 6-decimal stable mints:
| Token | Mint |
| ----- | ---------------------------------------------- |
| USDC | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |
| USDT | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` |
| PYUSD | `2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo` |
| xoUSD | `xoUSDq85Rjsb6SbUwJyreFgeWQvxdkT7R3c3g7s6p5Y` |
Integration is permissionless at **default rates** read from `pair_state`.
**Custom pricing** is delivered through Swaps-signed router proofs (covered
below) — [reach out to us](https://console.swaps.xyz) to get set up.
## Fees and `pair_state`
Each tradeable pair has a `pair_state` PDA holding directional fees, refreshed
continuously by the Swaps pricing keeper:
* **Seeds:** `["pair_state", mint_x, mint_y]` where `mint_x < mint_y`
(lexicographic pubkey sort — the lower-sorted mint is canonical X).
* **Fields:** `mint_x`, `mint_y`, `x_to_y_fee_bps`, `y_to_x_fee_bps`,
`last_updated_slot`, `bump`.
Read the `pair_state` for your pair to quote the default rate for each
direction.
## The `swap` instruction
```text theme={null}
swap(amount_in: u64, minimum_amount_out: u64)
```
Accounts, in order:
| # | Account | Notes |
| -- | ----------------------------- | --------------------------------------------------- |
| 1 | `user` | Signer |
| 2 | `exchange_state` | Program state PDA |
| 3 | `mint_in` | Input mint |
| 4 | `mint_out` | Output mint |
| 5 | `token_state_in` | Token state PDA for the input mint |
| 6 | `token_state_out` | Token state PDA for the output mint |
| 7 | `token_vault_in` | Program vault for the input mint (writable) |
| 8 | `token_vault_out` | Program vault for the output mint (writable) |
| 9 | `user_token_account_in` | User's input token account (writable) |
| 10 | `recipient_token_account_out` | Recipient's output token account (writable) |
| 11 | `pair_state` | Pair fee state PDA |
| 12 | `instructions` | Instructions sysvar (used to read the router proof) |
| 13 | `system_program` | |
| 14 | `associated_token_program` | |
| 15 | `token_program_in` | Token program of the input mint |
| 16 | `token_program_out` | Token program of the output mint |
An address lookup table is available to keep transactions compact:
```
9gMXVHfEV9L4vnQEHG879VwfYrcupBwKe9kRBFsLQoYg
```
## Custom pricing — the router proof
Without a proof, swaps execute at the default `pair_state` rates. A **router
proof** — an Ed25519 signature produced by the Swaps router key — overrides the
rate for a specific swap. This is how partners receive custom pricing.
The proof is supplied as an Ed25519 signature-verification precompile
instruction that **must be at transaction instruction index 0**; the program
reads it through the Instructions sysvar. The signed message is 118 bytes:
| Field | Size | Encoding |
| ---------- | -------- | ----------------- |
| `"swap"` | 4 bytes | ASCII |
| `user` | 32 bytes | Pubkey |
| `mintIn` | 32 bytes | Pubkey |
| `mintOut` | 32 bytes | Pubkey |
| `amountIn` | 8 bytes | u64 little-endian |
| `expiry` | 8 bytes | i64 little-endian |
| `rateBps` | 2 bytes | u16 little-endian |
The `stableswap-sdk` npm package's `buildRouterProofMessage` and
`buildRouterProofInstruction` helpers are the reference implementation for this
encoding. Proofs are signed by Swaps — contact us to set up custom pricing.
## Errors
| Error | Cause |
| ----------------------- | -------------------------------------------- |
| `Frozen` | Exchange is currently frozen |
| `ZeroAmount` | Amount must be greater than zero |
| `InsufficientLiquidity` | Insufficient liquidity in the output vault |
| `SlippageExceeded` | Output is less than `minimum_amount_out` |
| `InvalidPairState` | Wrong `pair_state` account for the mints |
| `InvalidProof` | Router proof signature or message is invalid |
| `ProofExpired` | Router proof `expiry` has passed |
## Related
* [Stableswap on EVM](/protocol-reference/stableswap-evm) — the same protocol
behind the GhostExchange interface.
* [Stableswaps via the API](/guides/stableswaps) — the same liquidity through
a single `getAction` call.
# Best Practices
Source: https://docs.swaps.xyz/resources/best-practices
Get the most out of Swaps with our multi-chain development best practices.
## Pay attention to named vs. alt VMs
We classify chains by their execution environment. Our routing and transaction tracking primarily differs based on whether chains in your quote request include named vs. alt VMs. The `/getAction` response includes a [`vmId` field](/swap-api-reference/get-action#response-vm-id) that informs you which routing strategy will applies to your quote. You can also find this information on the Supported Chains page.
**When the `vmId` is `alt-vm`, please note that you must:**
1. Use the `/getPaths` endpoint to validate your destination token andj source token swap amount ([reference](/resources/best-practices#cache-available-paths)).
2. Register your transaction after broadcasting to initiate tracking ([reference](/guides/track-transactions#register-transaction)).
## Cache available paths
The [`/getPaths` endpoint](/swap-api-reference/get-paths) returns all available destinations for a given source token and set of filters. For alternative VMs, there may be minimum or maximum transfer amounts, or only a subset of the total tokens available on a network may be supported. We recommend caching available paths with \~15 minute expiries and checking against it as part of the [quoting process](/guides/swap#create-a-swap-transaction) to ensure your requests are executable.
For named VMs, it is safe to assume any token in any size is available.
## Manage permissioned functions
Some smart contracts include permissioned functions that resolve based on the wallet address sending the transaction. Often, you will see a check based on the `msg.sender`.
Cross-chain transactions are executed from relayer accounts, not directly from the user's wallet. As a result, a `msg.sender` check will fail even if it *actually is* the authorized wallet address sending the source chain transaction.
`msg.sender` checks are typically impractical in a multi-chain context. Instead, we recommend a signature-based approach to authentication.
For example, the [Songcamp](https://song.camp/) team wanted users to mint NFTs without metadata and then send a permissioned function to write metadata to the NFT based on certain traits of the user's wallet address.
To enable cross-chain execution while still authenticating wallets, Songcamp included a hash of the user's wallet address in the transaction calldata and recovered the singer's address as follows:
[View full contract](https://explorer.zora.energy/address/0x38898cadb5241121620a81e7bca47eab8a87402a?tab=contract)
```solidity theme={null}
function multiWriteToDiscSignature( // [!code focus]
uint256[] memory tokenIds, // [!code focus]
uint256[] memory songSelections, // [!code focus]
bytes memory signature // [!code focus]
) public {
require(
tokenIds.length == songSelections.length,
"tokenIds and songSelections arrays must have the same length"
);
//Constructing the signed hash for signer address recovery // [!code focus]
bytes32 messageHash = keccak256(abi.encodePacked(tokenIds, songSelections)); // [!code focus]
bytes32 ethSignedHash = keccak256( // [!code focus]
abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash) // [!code focus]
); // [!code focus]
address signer = recoverSigner(ethSignedHash, signature); // [!code focus]
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 songChoiceId = songSelections[i];
// Check if CdMemory is not written before allowing an update
CdMemory storage cd = readCdMemory[tokenId];
require(
ownerOf(tokenId) == signer,
"Only the owner can set CdMemory"
);
require(
songChoiceId >= 1 && songChoiceId <= 5,
"Invalid song choice ID"
);
require(!cd.written, "One or more tokens are already written.");
// Update CdMemory and mark it as written
cd.writerAddress = signer;
cd.songChoiceId = songChoiceId;
cd.written = true;
writeCount += 1;
emit CdMemorySet(tokenId, signer, songChoiceId);
}
}
//Helper function to determine signer address based on the signed hash and the signature
function recoverSigner( // [!code focus]
bytes32 ethSignedHash, // [!code focus]
bytes memory signature // [!code focus]
) public pure returns (address) { // [!code focus]
// Extract the r, s, and v values from the signature // [!code focus]
(bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); // [!code focus]
// Recover and return the signer address // [!code focus]
return ecrecover(ethSignedHash, v, r, s); // [!code focus]
}
//Helper Function to split signature into RSV values // [!code focus]
function splitSignature( // [!code focus]
bytes memory signature // [!code focus]
) public pure returns (bytes32 r, bytes32 s, uint8 v) { // [!code focus]
require(signature.length == 65, "Invalid signature length"); // [!code focus]
assembly { // [!code focus]
// Slice the r, s, and v components from the signature // [!code focus]
r := mload(add(signature, 32)) // [!code focus]
s := mload(add(signature, 64)) // [!code focus]
v := byte(0, mload(add(signature, 96))) // [!code focus]
} // [!code focus]
} // [!code focus]
```
# Supported Chains
Source: https://docs.swaps.xyz/resources/chain-list
Swaps currently supports the following chains.
Swaps has integrated natively with Rollup-as-a-Service providers and is constantly adding new chains. Check back regularly for the latest list.
# Terms of Service
Source: https://docs.swaps.xyz/resources/terms-of-service
Last updated: November 3, 2025
These Terms of Service (these “Terms” or this “Agreement”) govern your access to and use of the products, services, and properties operated by Swaps XYZ Ltd, a British Virgin Islands business company organized under the laws of the British Virgin Islands (“Company”, “we”, “us”, or “our”), including: (a) our publicly available application programming interfaces, software development kits, developer tools, documentation, sandbox environments, and related developer products (collectively, the “APIs”); (b) our web application(s), site(s), and interfaces used to discover prices, route, and submit transactions across supported blockchain networks (collectively, the “App” or the “UI”); and (c) certain smart contracts that we develop and deploy on supported blockchain networks (the “Swaps Smart Contracts”; together with the APIs and the App, collectively, the “Services”). By accessing or using the Services, you agree to be bound by this Agreement. If you do not agree, you must not use the Services.
**ARBITRATION NOTICE AND CLASS ACTION WAIVER**: EXCEPT FOR CERTAIN TYPES OF DISPUTES DESCRIBED IN SECTION 17, YOU AGREE THAT DISPUTES BETWEEN YOU AND US WILL BE RESOLVED BY BINDING INDIVIDUAL ARBITRATION, YOU WAIVE YOUR RIGHT TO JURY TRIAL, AND YOU WAIVE YOUR RIGHT TO PARTICIPATE IN A CLASS ACTION LAWSUIT, CLASS ARBITRATION, OR ANY OTHER REPRESENTATIVE PROCEEDING. YOU MAY OPT OUT OF ARBITRATION WITHIN THIRTY (30) DAYS AS DESCRIBED IN SECTION 17.
By accepting these Terms, you also agree to the mandatory arbitration provision and class action waiver in Section 17.
**1. Eligibility and Authority**
You must be at least 18 years old (or the age of majority where you reside, if higher) and able to form a binding contract. If you accept these Terms on behalf of a company or other legal entity, you represent that you have authority to bind that entity, and “you” will refer to that entity. You represent and warrant that (a) you are not, and are not owned or controlled by (directly or indirectly), any person or entity that is listed on, or otherwise subject to, any sanctions or restricted-party list administered or enforced by the British Virgin Islands, the United States, the United Kingdom, the European Union, the United Nations, or any other applicable sanctions authority; (b) you are not a citizen or resident of, located in, or organized in any jurisdiction that is embargoed or comprehensively sanctioned by any of the foregoing authorities; and (c) your use of the Services is lawful and does not violate any applicable law, rule, or regulation. In addition, you agree that you will at all times comply with all laws, rules, and regulations applicable to you and your access and use of the Services, including, without limitation, anti-money laundering, counter-terrorist financing, sanctions, export control, consumer protection, tax, and securities laws.
You may not use, export, re‑export, or transfer the Services except as authorized by the laws of the British Virgin Islands and all other applicable laws, including those of the United States, the United Kingdom, the European Union, and any jurisdiction in which the Services are accessed. You represent that you are not located in, under the control of, or a national or resident of any country or region subject to comprehensive sanctions administered or enforced by the British Virgin Islands, the United States, the United Kingdom, the European Union, or the United Nations, and you are not on any government list of prohibited or restricted parties.
We may suspend, restrict, or terminate access to all or any portion of the Services, including blocking transactions, in our discretion, including for suspected violations of this Agreement or applicable law, or where required by subpoena, court order, or binding order of a governmental authority.
**2. Modifications to These Terms**
We may update these Terms from time to time in our discretion. If we make changes, we will provide notice by updating the “Last updated” date. Unless otherwise stated, changes are effective immediately, and your continued use of the Services confirms your acceptance. If you do not agree to the amended Terms, you must stop using the Services.
**3. Services**
We provide software Services, including APIs and an App user interface, that enable you to discover prices and route, sign, and submit transactions to supported public blockchain networks via third-party wallet software and underlying smart contract protocols (collectively, **“Protocols”**). Protocols include both (i) the Swaps Smart Contracts and (ii) smart contracts and other software authored or operated by third parties. The Swaps Smart Contracts may be open-source and made available under applicable open-source licenses, and certain Swaps Smart Contracts may be upgradeable or subject to governance or administrative controls described in the relevant documentation. We do not operate a virtual currency or derivatives exchange platform, do not offer trade execution or clearing services, and do not act as a broker, payment processor, financial institution, creditor, investment adviser, or commodity trading adviser.
You may be required to connect a compatible third-party digital wallet to use portions of the App and to create an account to use portions of the APIs (each, an **“Account”**). All transactions are effected by your wallet software and the applicable network(s). You are solely responsible for securing your wallet, maintaining accurate Account information, and promptly notifying us of any suspected breach of your Account or API credentials. If you are a developer using the APIs, you are responsible for the acts and omissions of your end users and for implementing appropriate authentication, rate limiting, security, and compliance measures.
We do not hold, have access to, or retain private keys. You retain full custody and control of your digital assets at all times and bear all risk of loss. We do not and cannot control the operation of any blockchain, Protocol, or mempool, or the availability, security, or functionality of third-party wallets, bridges, or other third-party services. To the fullest extent permitted by law, the Services (including the Swaps Smart Contracts and any third-party Protocols) are provided on an “as is” and “as available” basis, and we cannot reverse, block, or recover transactions you initiate.
**4. License and Usage**
Subject to your compliance with these Terms, we grant you a limited, revocable, non-exclusive, non-transferable, non-sublicensable license to access and use the APIs and related documentation solely to build applications that interact with supported Protocols and networks through our Services. You must not: (a) use the APIs in a manner that degrades or harms the Services or Protocols; (b) circumvent or exceed documented rate limits; (c) scrape, index, or bulk export data except as permitted by documentation; (d) reverse engineer, decompile, or derive source code except to the extent permitted by applicable open-source licenses; (e) cache or store data in violation of our data retention policies; (f) use the APIs to develop or operate a substantially similar aggregation or routing API service that is offered commercially to third parties, without our prior written consent; or (g) remove, obscure, or alter any proprietary notices.
Except for open‑source software components governed by their respective licenses, the Services and all content, interfaces, designs, and software provided by us are owned by or licensed to us and are protected by intellectual property laws. We grant you no rights other than those expressly stated in this Agreement. Certain Protocols and components, including some Swaps Smart Contracts, may be made available under open‑source licenses and/or posted in public repositories. Your use of such components is subject to the applicable open‑source license(s), which may grant rights different from or additional to those contained in these Terms. Nothing in these Terms limits your rights under any applicable open‑source license.
We may update, deprecate, or discontinue any API, endpoint, parameter, or feature with or without notice. You are responsible for implementing updates and changes to maintain compatibility.
**5. User Content and Feedback**
If you upload, submit, store, or otherwise make available text, data, code samples, documentation, or other content through the Services (**“User Content”**), you retain ownership of your User Content, but you grant us a worldwide, non-exclusive, royalty-free, sublicensable, and transferable license to use, host, reproduce, modify, create derivative works, distribute, display, and perform your User Content for purposes of operating, improving, securing, and promoting the Services. You also grant other users a limited license to access and use your publicly shared User Content through the Services. You represent and warrant you have all rights necessary to grant these licenses.
If you provide suggestions, comments, or other feedback (**“Feedback”**), we may use, disclose, and otherwise exploit the Feedback without restriction or obligation to you.
**6. Changes; Suspension; Termination**
We may modify, suspend, or discontinue any part of the Services at any time, with or without notice, for any reason, including security incidents, maintenance, or changes in Protocols or third-party dependencies. We are not liable for any losses resulting from any modification, suspension, or termination. All of these Terms will survive any termination of your access to the Services, regardless of the reasons for its expiration or termination, in addition to any other provision which by law or by its nature should survive.
**7. Fees**
* **Network or protocol fees.** Transactions on supported networks may require payment of network fees (e.g., “gas”) or other protocol charges (**“Network Fees”**) paid to blockchain networks or Protocols to process transactions. Under the Swaps Smart Contracts, Network Fees may be paid in the native gas token required by the underlying network, or another supported token. You are solely responsible for all Network Fees.
* **Service fees.** We may charge fees for certain transactions or features, including but not limited to limit orders, swaps on specified networks, advanced routing, and protocol execution services that allow transactions without holding native gas tokens (**“Aggregator Services”**), and similar features. Where applicable, such fees will be disclosed in the transaction details presented to you before you authorize a transaction, or in API documentation for developers.
* **Changes.** We may add, modify, or discontinue fees in our discretion. Any changes will be reflected in the UI or API response prior to transaction authorization or documented in the API documentation.
You are solely responsible for all taxes arising from your use of the Services and your transactions.
**8. Third-Party Services and Data**
The Services may rely on or link to third-party services, smart contracts, wallets, bridges, RPC providers, market makers, data sources, or other services not operated by us (collectively, **“Third-Party Services”**). We do not control and are not responsible for Third-Party Services, including the accuracy, timeliness, completeness, reliability, availability, or security of their content or functionality. Your use of Third-Party Services is at your own risk and may be subject to separate terms and policies.
**9. Risk Disclosure**
You understand and agree that:
* Digital assets and Protocols are highly volatile and subject to market, technological, regulatory, and cybersecurity risks. Prices and costs (including Network Fees) can change rapidly and unpredictably.
* Protocols and networks are operated by third parties or communities. We do not control, and are not responsible for, their operation, security, forks, upgrades, reorgs, censorship, or downtime.
* Transactions are generally irreversible and may fail, revert, be delayed, or execute at a different price than expected due to network conditions, slippage, MEV, or other factors.
* Anyone can create tokens; we make no representation about any token’s attributes, legal status, or suitability. You must conduct your own research and ensure you are legally permitted to transact in any token.
You assume all risks associated with your use of the Services and your interactions with Protocols and digital assets.
**10. Acceptable Use**
You agree not to, and not to enable or encourage any third party to:
* Violate any applicable law (including AML/CFT, sanctions, export, and securities laws).
* Interfere with, disrupt, or degrade the Services; introduce malware; bypass or circumvent security or access controls; access non-public areas; or scrape or harvest content or data except as expressly permitted by API documentation.
* Engage in market manipulation or misconduct (including front-running, wash trading, spoofing, layering, pump-and-dump schemes).
* Use any VPN, proxy, Tor routing, or similar technology to obscure your location for the purpose of accessing the Services from a jurisdiction where the Services are restricted or prohibited.
* Use the Services to conduct regulated financial activities that require registration or licensing (including issuing or transacting in securities or derivatives) unless you have all necessary approvals and we have provided prior written consent.
* Use the Services to conduct or facilitate fundraising activities that constitute or may constitute an offering of securities or similar regulated instruments.
* Engage in toxic or abusive order flow practices that systematically exploit stale quotes, latency, or information asymmetries against liquidity providers.
* Use the APIs to develop or operate a substantially similar aggregation or routing API service that is offered commercially to third parties, without our prior written consent.
We may investigate and refer suspected violations to law enforcement and regulators and disclose information as required by law or to protect rights, safety, and property.
**11. Privacy**
Your use of the Services is governed by the MoonPay Privacy Policy, available at [https://www.moonpay.com/legal/privacy\_policy](https://www.moonpay.com/legal/privacy_policy). By using the Services, you consent to our collection and use of information as described in the Privacy Policy.
**12. Electronic Notices**
You consent to receive communications from us electronically, including by email, in-Service messages, or postings on the Services. Such communications satisfy any legal requirement that communications be in writing. You are responsible for maintaining current contact information. You may request additional electronic copies of notices by contacting us at [support@moonpay.com](mailto:support@moonpay.com).
**13. Warranty Disclaimers**
To the maximum extent permitted by law, the Services (and any content or functionality) are provided “AS IS” and “AS AVAILABLE,” without warranties of any kind, whether express, implied, statutory, or otherwise, including implied warranties of merchantability, fitness for a particular purpose, title, quiet enjoyment, accuracy, and non-infringement. Without limiting the foregoing, we make no representation or warranty regarding the functionality, security, availability, or suitability of any Protocols (including the Swaps Smart Contracts) or any third-party blockchain network. We do not warrant that the Services will be uninterrupted, secure, or error-free, that defects will be corrected, or that data will be accurate, current, or complete.
**14. Indemnification**
To the fullest extent permitted by law, you will indemnify, defend, and hold harmless Company and its affiliates, and their respective directors, officers, employees, contractors, and agents, from and against any claims, losses, liabilities, damages, costs, and expenses (including reasonable attorneys’ fees) arising out of or relating to: (a) your access to or use of the Services (including your interaction with any Protocols or Swaps Smart Contracts); (b) your violation of these Terms or applicable law; (c) your User Content; (d) your applications, products, or services that use the APIs; or (e) any dispute between you and any third party. We may control the defense and settlement of any claim subject to indemnification, and you will cooperate with us.
**15. Limitation of Liability**
To the fullest extent permitted by law, in no event will we be liable for any indirect, incidental, special, punitive, exemplary, or consequential damages, or for any loss of profits, revenues, goodwill, data, or other intangible losses, arising out of or relating to your use of or inability to use the Services, whether based in contract, tort, negligence, strict liability, or otherwise, even if we have been advised of the possibility of such damages.
Our aggregate liability arising out of or relating to these Terms or the Services will not exceed the greater of: (a) one hundred U.S. dollars (US\$100); or (b) the amount of fees retained by us from you in connection with the transaction or incident giving rise to the claim during the twelve (12) months immediately preceding the event giving rise to liability. The foregoing cap does not limit your payment obligations or indemnity obligations.
Some jurisdictions do not allow certain limitations of liability; in such jurisdictions, our liability will be limited to the maximum extent permitted by law.
**16. Release**
To the fullest extent permitted by applicable law, in consideration for being allowed to use the Services, you hereby release and forever discharge the Company and its affiliates, and their respective shareholders, members, directors, officers, employees, attorneys, agents, representatives, suppliers, licensors, and contractors (collectively, the **“Released Parties”**) from, and you hereby waive, each and every past, present, and future dispute, claim, controversy, demand, right, obligation, liability, action, and cause of action of every kind and nature (including for personal injuries, death, and property damage) that arises out of or relates to the Services, including any interactions with, or act or omission of, other users, any Third-Party Services, any Protocols or Swaps Smart Contracts, or any third-party blockchain networks.
**California Waiver.** If you are a California resident, you waive California Civil Code § 1542 (and any substantially similar law), which states: **“A general release does not extend to claims that the creditor or releasing party does not know or suspect to exist in his or her favor at the time of executing the release and that, if known by him or her, would have materially affected his or her settlement with the debtor or released party.”**
**17. Dispute Resolution and Arbitration**
PLEASE READ THIS SECTION CAREFULLY. IT REQUIRES YOU TO ARBITRATE CERTAIN DISPUTES AND LIMITS THE MANNER IN WHICH YOU CAN SEEK RELIEF.
* **Informal resolution.** Before initiating arbitration, the initiating party must send a written notice of the dispute to the other party at [support@moonpay.com](mailto:support@moonpay.com) and attempt to resolve it informally within 30 days.
* **Arbitration agreement.** Except as expressly provided below, any dispute, claim, or controversy arising out of or relating to these Terms or the Services (including any question regarding their existence, validity, or termination) will be finally resolved by binding, individual arbitration administered by the BVI International Arbitration Centre (**“BVI IAC”**) under the BVI IAC Arbitration Rules, which are incorporated by reference. The arbitration agreement, including its interpretation and enforcement, is governed by the Arbitration Act, 2013 of the British Virgin Islands.
* **Seat, venue, governing law, and language.** The seat and legal place of arbitration will be Road Town, Tortola, British Virgin Islands. The arbitration will be conducted in English. Unless you and we agree otherwise, if you are a consumer, any hearings may be conducted by video or telephone. The arbitrator will have exclusive authority to determine issues of arbitrability, procedure, jurisdiction, and remedies. The substantive laws of the British Virgin Islands will govern the merits of any dispute.
* **Carve-Outs.** The following disputes are not subject to arbitration: (a) either party may seek interim or injunctive relief, including for intellectual property infringement or misuse of confidential information, in the courts of the British Virgin Islands; and (b) if you are a natural person, you may bring an individual claim in a small claims court of competent jurisdiction.
* **Class action waiver.** YOU AND WE AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN AN INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS, COLLECTIVE, CONSOLIDATED, OR REPRESENTATIVE PROCEEDING. THE ARBITRATOR MAY AWARD RELIEF ONLY IN FAVOR OF THE INDIVIDUAL PARTY SEEKING RELIEF.
* **Confidentiality.** The parties and the arbitrator will maintain the confidentiality of the arbitration to the extent permitted by law and the applicable arbitration rules.
* **Fees.** Filing and administrative fees will be allocated as provided in the applicable BVI IAC rules. Each party will bear its own attorneys’ fees and costs unless the arbitrator awards fees under applicable law.
* **Opt-out.** You may opt out of this arbitration agreement within 30 days of first accepting these Terms by emailing [support@moonpay.com](mailto:support@moonpay.com) with your name, account email or wallet address, and a clear statement of your intent to opt out. If you opt out, you agree to resolve disputes exclusively in the courts specified in Section 18.
* **Mass filings.** If 100 or more substantially similar arbitration demands are filed by or with the assistance of the same law firm or organization, the parties agree to cooperate in good faith with the BVI IAC to implement appropriate protocols (including batching and bellwether proceedings) to minimize costs and promote efficient resolution.
**18. Governing Law**
This Agreement and any dispute not subject to arbitration will be governed by and construed in accordance with the laws of the British Virgin Islands, without regard to conflict of laws rules that would cause the application of the laws of any other jurisdiction. The courts of the Eastern Caribbean Supreme Court sitting in the High Court of Justice of the Virgin Islands (British) will have exclusive jurisdiction over any dispute not subject to arbitration, and the parties consent to personal jurisdiction and venue in those courts.
**19. Consumer Notices**
In accordance with California Civil Code § 1789.3, you may contact the Complaint Assistance Unit of the Division of Consumer Services of the California Department of Consumer Affairs in writing at 1625 North Market Blvd., Suite N-112, Sacramento, CA 95834, or by telephone at (800) 952-5210.
**20. Miscellaneous**
This Agreement is the entire agreement between you and us regarding the Services and supersedes any prior agreements regarding the Services. We may assign this Agreement, in whole or in part, without notice. You may not assign or transfer this Agreement without our prior written consent. If any provision is held invalid or unenforceable, that provision will be enforced to the maximum extent permissible and the remaining provisions will remain in full force and effect. No waiver is effective unless in writing and signed by an authorized representative of the waiving party. There are no third-party beneficiaries to this Agreement. Legal notice and questions about these Terms may be sent to [support@moonpay.com](mailto:support@moonpay.com).
# Get Action
Source: https://docs.swaps.xyz/swap-api-reference/get-action
/swap-api-reference/openapi.json get /getAction
Generates a transaction for cross-chain swaps, bridges, and calls. The action includes transaction data, routing information, and fee calculations for executing the requested operation.
# Get Chain List
Source: https://docs.swaps.xyz/swap-api-reference/get-chain-list
/swap-api-reference/openapi.json get /getChainList
Retrieve a list of supported chains, their names, and virtual machine identifiers. Raw data for the [supported chains list](/resources/chain-list).
# Get Paths
Source: https://docs.swaps.xyz/swap-api-reference/get-paths
/swap-api-reference/openapi.json get /getPaths
Retrieves all available token paths across supported chains with configurable filtering options. It’s recommended to call this endpoint after selecting the source and destination tokens to validate route eligibility.
# Get Quote
Source: https://docs.swaps.xyz/swap-api-reference/get-quote
/swap-api-reference/openapi.json get /getQuote
Returns a non-binding reference price for a cross-chain swap. Unlike `GET /getAction`, this endpoint never allocates a deposit address, builds transaction calldata, or triggers wallet-screening checks — it's priced-only, safe to call at high frequency (e.g. to refresh a quote widget), and always uses `swap-action` semantics regardless of any `actionType` you pass.
`sender` and `recipient` are not accepted as inputs — the endpoint prices the route using internal placeholder addresses, since no transaction is produced. If you need a signable transaction, use `GET /getAction` instead.
# Get Status
Source: https://docs.swaps.xyz/swap-api-reference/get-status
/swap-api-reference/openapi.json get /getStatus
Retrieve the status and details of a transaction by transaction ID.
# Get Token List
Source: https://docs.swaps.xyz/swap-api-reference/get-token-list
/swap-api-reference/openapi.json get /getTokenList
Retrieve the list of supported tokens for a given chain, or for all supported chains if no chainId is specified.
# Get Transactions
Source: https://docs.swaps.xyz/swap-api-reference/get-transactions
/swap-api-reference/openapi.json get /getTransactions
Retrieve paginated transaction history with optional filtering.
# Overview
Source: https://docs.swaps.xyz/swap-api-reference/overview
Flexible APIs for lightning-fast cross-chain transactions.
## Endpoint reference
### Core
| API | Description |
| :--------------------------------------------------------------- | :------------------------------------------------------------- |
| [Get Action](/swap-api-reference/get-action) | Generate a bridge, swap, or cross-chain call transaction. |
| [Get Status](/swap-api-reference/get-status) | Track the status of a transaction based on its hash or ID. |
| [Register Transaction](/swap-api-reference/register-transaction) | Trigger indexing for one or multiple broadcasted transactions. |
### Data
| API | Description |
| :------------------------------------------------------- | :--------------------------------------------------- |
| [Get Transactions](/swap-api-reference/get-transactions) | Return transaction history based on desired filters. |
### Utilities
| API | Description |
| :--------------------------------------------------- | :------------------------------------------------------------------------------ |
| [Get Paths](/swap-api-reference/get-paths) | Retrieve available swap routes for given source token based on desired filters. |
| [Get Chain List](/swap-api-reference/get-chain-list) | Return list of all supported chains and their `VmId`s. |
### Prediction Markets
Looking for Polymarket trading, workflows, and market data? Those endpoints live in the [Prediction Market Reference](/prediction-market-reference/overview).
## Authentication
All API endpoints require authentication using API keys passed via the `x-api-key` header. We have provided a highly ratelimited API key for testing in the API playground.
Create a key in the [Console](https://console.swaps.xyz).
## Related Resources
* [Send your first swap](/guides/swap) - Learn how to broadcast swap transactions
* [Call smart contracts across chains](/guides/calldata-call) - Deposit into [Aave](https://aave.com) on Base using ETH on Arbitrum
# Register Transaction
Source: https://docs.swaps.xyz/swap-api-reference/register-transaction
/swap-api-reference/openapi.json post /registerTxs
Register transactions for indexing. Mandatory for non EVM transactions.
# Submit Gasless Transaction
Source: https://docs.swaps.xyz/swap-api-reference/submit-gasless-transaction
/swap-api-reference/openapi.json post /submitTx
Submits signed executions obtained from a gasless `GET /getAction` response for relay broadcast. The backend validates each signature, simulates the transactions, then broadcasts them via the configured relay provider.
Call this endpoint only when `executionsType` is `GASLESS` in the `getAction` response. Sign all items in the `executions` array in order before submitting.