Skip to main content
API Reference: GET /getAction · POST /submitTx This guide extends the standard Swaps.xyz swap flow 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)

Requesting Gasless Execution

Add the optional gasless query parameter to your getAction request:
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:
FieldDescription
executionsType"GASLESS" — indicates relay execution
executionsOrdered array of signing steps
relayerFeeFee charged by the relay, denominated in USDT. If non-zero, the user must hold USDT in addition to the source token
txIdUnique action ID returned by getAction — required when calling POST /submitTx
// 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",
      to: "TTRr81XJt6zESpJw2zHgJNAsxcsyT5MVYv",
      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.

Executing Gasless Transactions

1

Check executionsType

Always check the response before proceeding:
if (actionResponse.executionsType !== "GASLESS") {
  // Fall back to standard broadcast
  return broadcastStandardTx(actionResponse.tx);
}
2

Sign each execution in order

Iterate executions and sign each step with the appropriate wallet method:
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.
3

Submit to POST /submitTx

Send the signed executions along with the txId from the getAction response:
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

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).
  • 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

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";
  to: string; // verifying contract address
  data: Eip712Data;
}

type Execution = EvmTransactionSignExecution | EvmSignTypedDataExecution;

interface Eip712Data {
  domain: { name: string; version: string; chainId: number; verifyingContract: string };
  types: Record<string, { name: string; type: string }[]>;
  message: Record<string, unknown>;
}

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;
}