> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swaps.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Gasless Transactions

> Execute sponsored meta-transactions without requiring users to hold native tokens for gas.

export const Callout = ({type = 'info', children}) => {
  const borderColor = ({
    info: '#007acc',
    warning: '#FFC263',
    danger: '#d9534f',
    success: '#00C256'
  })[type] || '#ccc';
  const bgColor = ({
    info: '#f3f9ff',
    warning: '#FFF2DE',
    danger: '#f7f2f1',
    note: '#f8f8f8',
    tip: '#f1f1f8',
    success: '#E0FFEE'
  })[type] || '#f3f9ff';
  return <div style={{
    borderLeft: `4px solid ${borderColor}`,
    backgroundColor: bgColor,
    padding: '0.5rem',
    borderRadius: '12px',
    margin: '1rem 0',
    fontSize: '14px'
  }}>
      {children}
    </div>;
};

**API Reference:** [GET /getAction](/swap-api-reference/get-action) · [POST /submitTx](/swap-api-reference/submit-tx)

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)

<Callout type="info">
  Gasless execution requires your API key to have gasless enabled. Contact the Swaps team if you need access.
</Callout>

***

## 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

<Steps>
  <Step title="Check executionsType">
    Always check the response before proceeding:

    ```typescript theme={null}
    if (actionResponse.executionsType !== "GASLESS") {
      // Fall back to standard broadcast
      return broadcastStandardTx(actionResponse.tx);
    }
    ```
  </Step>

  <Step title="Sign each execution in order">
    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.
  </Step>

  <Step title="Submit to POST /submitTx">
    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
    ```
  </Step>
</Steps>

***

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