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

# Sending batch transactions

Batch transactions allow your app to send multiple operations in a single request. This is useful for executing multi-step workflows — such as approving and swapping tokens, distributing funds to multiple recipients, or performing complex DeFi operations — without requiring separate transactions for each step.

## How it works

Privy supports batch transactions on both EVM and Solana chains, but the mechanism differs for each.

### EVM

On EVM chains, Privy uses the [`wallet_sendCalls`](/api-reference/wallets/ethereum/wallet-send-calls) RPC method to send multiple calls in a single atomic batch. Under the hood, Privy leverages [EIP-7702](https://eip7702.io/) to upgrade your user's wallet to a [Kernel smart contract](https://github.com/zerodevapp/kernel), which enables batched execution.

* **Without sponsorship**: The wallet executes a `self.execute` call on the upgraded Kernel contract, bundling all calls into a single atomic transaction.
* **With sponsorship**: Privy routes the batch through a **bundler** and **paymaster**, which covers the gas fees on behalf of the user. Set `sponsor` to `true` in the request body to enable this.

In both cases, batch calls are **atomic** — either all calls succeed, or the entire batch reverts. This ensures consistent state and prevents partial execution.

### Solana

On Solana, batch behavior is achieved by adding multiple instructions to a single `Transaction`. The Solana runtime processes all instructions in a transaction sequentially, and the transaction is **atomic** — if any instruction fails, the entire transaction is reverted.

Learn more about sending Solana transactions in the [Solana recipes](/recipes/solana/send-sol).

## Sending batch transactions on EVM

Use the `wallet_sendCalls` method via the Privy wallets RPC endpoint to send multiple calls in a single batch.

### Example: sending two transfers

<View title="NodeJS" icon="node-js">
  ```typescript {skip-check} theme={"system"}
  import {PrivyClient} from '@privy-io/node';

  const privy = new PrivyClient({
    appId: process.env.PRIVY_APP_ID!,
    appSecret: process.env.PRIVY_APP_SECRET!
  });

  const response = await privy
    .wallets()
    .ethereum()
    .sendCalls('insert-wallet-id', {
      caip2: 'eip155:8453', // Base
      params: {
        calls: [
          {
            to: '0xRecipientAddress1',
            value: '0x2386F26FC10000' // 0.01 ETH in wei
          },
          {
            to: '0xRecipientAddress2',
            value: '0x2386F26FC10000' // 0.01 ETH in wei
          }
        ]
      }
    });
  ```
</View>

<View title="cURL" icon="terminal">
  ```bash theme={"system"}
  curl --request POST \
    --url https://api.privy.io/v1/wallets/{wallet_id}/rpc \
    --header 'Authorization: Basic <encoded-value>' \
    --header 'Content-Type: application/json' \
    --header 'privy-app-id: <privy-app-id>' \
    --data '{
    "method": "wallet_sendCalls",
    "caip2": "eip155:8453",
    "chain_type": "ethereum",
    "params": {
      "calls": [
        {
          "to": "0xRecipientAddress1",
          "value": "0x2386F26FC10000"
        },
        {
          "to": "0xRecipientAddress2",
          "value": "0x2386F26FC10000"
        }
      ]
    }
  }'
  ```
</View>

### Example: approve and swap in one batch

A common use case is combining an ERC-20 approval with a swap in a single atomic batch:

```typescript theme={"system"}
export {};
declare const swapRouterAbi: any;
declare const swapParams: any;
declare const privy: any;

import {encodeFunctionData, erc20Abi} from 'viem';

// Encode the approval call
const approveData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'approve',
  args: ['0xSwapRouterAddress', BigInt(1000000)] // Approve 1 USDC (6 decimals)
});

// Encode the swap call (example ABI)
const swapData = encodeFunctionData({
  abi: swapRouterAbi,
  functionName: 'exactInputSingle',
  args: [swapParams]
});

const response = await privy
  .wallets()
  .ethereum()
  .sendCalls('insert-wallet-id', {
    caip2: 'eip155:8453',
    params: {
      calls: [
        {
          to: '0xUSDCContractAddress',
          data: approveData
        },
        {
          to: '0xSwapRouterAddress',
          data: swapData
        }
      ]
    }
  });
```

### With gas sponsorship

To sponsor gas for the batch transaction, set `sponsor` to `true`:

```bash theme={"system"}
curl --request POST \
  --url https://api.privy.io/v1/wallets/{wallet_id}/rpc \
  --header 'Authorization: Basic <encoded-value>' \
  --header 'Content-Type: application/json' \
  --header 'privy-app-id: <privy-app-id>' \
  --data '{
  "method": "wallet_sendCalls",
  "caip2": "eip155:8453",
  "chain_type": "ethereum",
  "sponsor": true,
  "params": {
    "calls": [
      {
        "to": "0xRecipientAddress1",
        "value": "0x2386F26FC10000"
      },
      {
        "to": "0xRecipientAddress2",
        "value": "0x2386F26FC10000"
      }
    ]
  }
}'
```

### Response

A successful request returns a `transaction_id` and the `caip2` chain identifier:

```json theme={"system"}
{
  "method": "wallet_sendCalls",
  "data": {
    "transaction_id": "b4966a89-8983-4b1b-a93a-b104799527f5",
    "caip2": "eip155:8453"
  }
}
```

Use the `transaction_id` to [track the status of the transaction](/api-reference/transactions/get).

## Sending batch transactions on Solana

On Solana, batching is done by adding multiple instructions to a single transaction. See the [Sending SOL](/recipes/solana/send-sol) recipe for a complete walkthrough.

Here is an example of batching two SOL transfers in a single transaction:

<View title="TypeScript" icon="terminal">
  ```typescript theme={"system"}
  import {Connection, PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL} from '@solana/web3.js';

  const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
  const fromPubkey = new PublicKey('insert-wallet-address');

  // Create a transaction with multiple instructions
  const transaction = new Transaction();

  // First transfer
  transaction.add(
    SystemProgram.transfer({
      fromPubkey,
      toPubkey: new PublicKey('0xRecipientAddress1'),
      lamports: 0.01 * LAMPORTS_PER_SOL
    })
  );

  // Second transfer
  transaction.add(
    SystemProgram.transfer({
      fromPubkey,
      toPubkey: new PublicKey('0xRecipientAddress2'),
      lamports: 0.02 * LAMPORTS_PER_SOL
    })
  );

  const {blockhash} = await connection.getLatestBlockhash();
  transaction.recentBlockhash = blockhash;
  transaction.feePayer = fromPubkey;
  ```
</View>

Then sign and send the transaction using any of the Privy SDKs as shown in the [Sending SOL](/recipes/solana/send-sol#2-send-the-transaction) recipe.

## Next steps

* [API reference: `wallet_sendCalls`](/api-reference/wallets/ethereum/wallet-send-calls) — Full parameter and response documentation
* [Gas sponsorship](/wallets/gas-and-asset-management/gas/overview) — Learn how to sponsor gas for batch transactions
* [Sending SOL](/recipes/solana/send-sol) — Solana transaction recipes
* [Sending USDC](/recipes/send-usdc) — Formatting ERC-20 token transfers
