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

# Send batched calls

> Execute several Tempo calls atomically in one transaction with sendTempoTransaction, and learn how gas is estimated for a batch

A Tempo transaction can carry several calls that execute atomically, so either every call takes effect or none does. This lets you pay several recipients, or approve and spend a token, in one transaction with one fee. A plain viem `sendTransaction` takes a single `to`, `data`, and `value`, so batches go through [`sendTempoTransaction`](/docs/javascript/reference/tempo/overview#send-a-tempo-transaction) from `@dynamic-labs-sdk/tempo/waas`.

## Send a batch

Pass the calls in `calls`. Each call takes an optional `to`, `data`, and `value`, and the SDK validates the address, the hex data, and the bigint value before it signs anything.

```typescript theme={"system"}
import { getTempoPublicClient } from '@dynamic-labs-sdk/tempo';
import type { TempoWalletAccount } from '@dynamic-labs-sdk/tempo';
import { sendTempoTransaction } from '@dynamic-labs-sdk/tempo/waas';
import { encodeFunctionData, erc20Abi, parseUnits } from 'viem';
import type { Hex } from 'viem';

const payTwoRecipients = async (walletAccount: TempoWalletAccount) => {
  const tokenAddress = '0xTip20TokenAddress...';

  const transferTo = (recipient: Hex) =>
    encodeFunctionData({
      abi: erc20Abi,
      args: [recipient, parseUnits('1.5', 6)],
      functionName: 'transfer',
    });

  const { transactionHash } = await sendTempoTransaction({
    calls: [
      { data: transferTo('0xFirstRecipient...'), to: tokenAddress },
      { data: transferTo('0xSecondRecipient...'), to: tokenAddress },
    ],
    walletAccount,
  });

  const publicClient = await getTempoPublicClient({ walletAccount });

  return publicClient.waitForTransactionReceipt({ hash: transactionHash as Hex });
};
```

`sendTempoTransaction` resolves with the hash once the signed transaction is submitted, so the example waits for the receipt on the client from `getTempoPublicClient` to confirm inclusion.

A batch needs at least one call. An empty `calls` array, or a call with a malformed address, data, or value, throws `TempoTransactionValidationError` before the wallet signs.

## How gas is estimated

The SDK estimates each call on its own, adds the estimates together, adds a 30% buffer, and never goes below 300,000 gas. If you pass `gas`, the SDK uses the larger of your value and its own estimate, so `gas` can raise the limit but cannot lower it.

Because every call is estimated separately, a call that only succeeds after an earlier call in the same batch cannot be estimated on its own. An example is a call that spends an allowance an earlier call grants. For a batch of several calls, or when you pass `gas`, the SDK counts 300,000 gas for a call whose estimate fails. A single call sent without `gas` throws the estimation error instead, so the failure is reported rather than signed over.

<Tip>
  If a batch depends on state that earlier calls create, pass a `gas` value that covers the whole batch. The SDK still raises it to its own estimate when that is higher.
</Tip>

## Related

* [Pay fees with a TIP-20 token](/docs/javascript/reference/tempo/pay-fees-with-a-token) sets the token that pays the fee for the batch.
* [Use parallel nonce lanes](/docs/javascript/reference/tempo/use-parallel-nonce-lanes) sends independent batches without queuing them behind each other.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.