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

# Setting up gas sponsorship

> Choose how gas fees are paid — sponsor them with app credits, or let users pay with stablecoins

Privy supports two gas payment modes. Choose the one that fits your app:

<Tabs>
  <Tab title="App pays">
    Your app's gas credits cover transaction fees for all users. Users transact without ever needing
    to hold ETH or native tokens.

    <Warning>
      Before enabling gas sponsorship in production, review the [security best
      practices](/wallets/gas-and-asset-management/gas/security) to help prevent abuse and protect gas
      balances.
    </Warning>

    ## Getting started

    <Steps>
      <Step title="Enable gas sponsorship in the dashboard">
        Go to the gas sponsorship tab in the [Privy
        Dashboard](https://dashboard.privy.io/apps?page=gas_sponsorship) and select **App pays**.

        <img src="https://mintcdn.com/privy-c2af3412/JsgMIYodAfYOjJAO/images/gas-sponsorship.png?fit=max&auto=format&n=JsgMIYodAfYOjJAO&q=85&s=67192ab8282dd9d4f560acc5e8650126" alt="images/gas-sponsorship.png" width="1843" height="1317" data-path="images/gas-sponsorship.png" />
      </Step>

      <Step title="Configure chains">
        Select which chains you want to enable sponsorship for. Sponsored requests may only come
        from the chains that you have configured. Want support for more networks?
        [Reach out to us!](mailto:sales@privy.io)
      </Step>

      <Step title="Send transaction requests">
        <Info>
          Apps **must** use [TEE execution](/security/wallet-infrastructure/architecture) in order
          to use our native gas sponsorship feature. Learn how to migrate
          [here](/recipes/tee-wallet-migration-guide)!
        </Info>

        <Tabs>
          <Tab title="Ethereum (React)">
            With the React SDK, use the `useSendTransaction` hook with `sponsor: true`:

            ```tsx highlight={12} theme={"system"}
            import {useSendTransaction, useWallets} from '@privy-io/react-auth';

            const {sendTransaction} = useSendTransaction();
            const {wallets} = useWallets();

            sendTransaction(
              {
                to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
                value: 100000
              },
              {
                sponsor: true // Enable gas sponsorship
              }
            );
            ```
          </Tab>

          <Tab title="Tempo (React)">
            With the React SDK, use the Tempo `useSendTransaction` hook with `sponsor: true`:

            ```tsx highlight={17} theme={"system"}
            import {useWallets} from '@privy-io/react-auth';
            import {useSendTransaction} from '@privy-io/react-auth/tempo';

            const {sendTransaction} = useSendTransaction();
            const {wallets} = useWallets();

            const {hash} = await sendTransaction(
              {
                transaction: {
                  type: 118,
                  chainId: 4217,
                  calls: [{to: '0xRecipientAddress', data: '0x'}]
                },
                wallet: wallets[0]
              },
              {
                sponsor: true
              }
            );
            ```

            <Info>
              For sponsored Tempo transactions, Privy adds `fee_payer_signature` before broadcast.
              This flow does not use EIP-7702 wallet upgrades, ERC-4337 user operations, or EVM
              paymasters.
            </Info>
          </Tab>

          <Tab title="Solana (React)">
            With the React SDK, use the `useSignAndSendTransaction` hook with `sponsor: true`:

            <Warning>
              On Solana, sponsored transactions can be abused through ATA rent refunds when
              transactions include `CloseAccount` instructions. Review [security best
              practices](/wallets/gas-and-asset-management/gas/security) before shipping to production.
            </Warning>

            ```tsx highlight={15} theme={"system"}
            import {useSignAndSendTransaction, useWallets} from '@privy-io/react-auth/solana';

            const {signAndSendTransaction} = useSignAndSendTransaction();
            const {wallets} = useWallets();

            const selectedWallet = wallets[0];

            const transaction = new Uint8Array([/* your encoded transaction */]);

            const result = await signAndSendTransaction({
              transaction: transaction,
              wallet: selectedWallet,
              options: {
                sponsor: true // Enable gas sponsorship
              }
            });
            ```

            <Info>
              **Allow transactions from the client**

              To sponsor transactions from your client-side application, enable this setting in
              your gas sponsorship dashboard configuration. When disabled, transactions can only
              be sponsored from your server.
            </Info>
          </Tab>

          <Tab title="Ethereum (REST API)">
            ```bash highlight={9} theme={"system"}
            $ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
              -u "<your-privy-app-id>:<your-privy-app-secret>" \
              -H "privy-app-id: <your-privy-app-id>" \
              -H "privy-authorization-signature: <authorization-signature-for-request>" \
              -H 'Content-Type: application/json' \
              -d '{
                  "method": "eth_sendTransaction",
                  "caip2": "eip155:1",
                  "sponsor": true,
                  "params": {
                      "transaction": {
                          "to": "0xE3070d3e4309afA3bC9a6b057685743CF42da77C",
                          "value": "0x2386F26FC10000"
                      }
                  }
              }'
            ```

            <Info>
              To sponsor transactions initiated from a client SDK, you may [relay the
              transaction](/controls/authorization-keys/keys/create/user/request) from your server.
            </Info>
          </Tab>

          <Tab title="Tempo (REST API)">
            ```bash highlight={9} theme={"system"}
            $ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
              -u "<your-privy-app-id>:<your-privy-app-secret>" \
              -H "privy-app-id: <your-privy-app-id>" \
              -H "privy-authorization-signature: <authorization-signature-for-request>" \
              -H 'Content-Type: application/json' \
              -d '{
                  "method": "eth_sendTransaction",
                  "caip2": "eip155:4217",
                  "sponsor": true,
                  "params": {
                      "transaction": {
                          "type": 118,
                          "calls": [
                              {
                                  "to": "0xRecipientAddress",
                                  "data": "0x"
                              }
                          ]
                      }
                  }
              }'
            ```

            <Info>
              Passing `sponsor: true` makes Privy populate the Tempo `fee_payer_signature` before
              broadcasting the transaction.
            </Info>
          </Tab>

          <Tab title="Ethereum (Node SDK)">
            ```typescript highlight={23} theme={"system"}
            import { PrivyClient } from '@privy-io/node';

            const privy = new PrivyClient({ appId: 'your-app-id', appSecret: 'your-app-secret' });

            const response = await privy
              .wallets()
              .ethereum()
              .sendTransaction(walletId, {
                caip2: 'eip155:1',
                params: {
                  transaction: {
                    to: '0x{address}',
                    value: '0x2386F26FC10000',
                  },
                },
                sponsor: true,
              });
            ```
          </Tab>

          <Tab title="Tempo (Node SDK)">
            ```typescript highlight={21} theme={"system"}
            import { PrivyClient } from '@privy-io/node';

            const privy = new PrivyClient({ appId: 'your-app-id', appSecret: 'your-app-secret' });

            const response = await privy
              .wallets()
              .ethereum()
              .sendTransaction(walletId, {
                caip2: 'eip155:4217',
                params: {
                  transaction: {
                    type: 118,
                    calls: [
                      {
                        to: '0xRecipientAddress',
                        data: '0x',
                      },
                    ],
                  },
                },
                sponsor: true,
              });
            ```
          </Tab>

          <Tab title="Solana (REST API)">
            <Warning>
              On Solana, sponsored transactions can be abused through ATA rent refunds when
              transactions include `CloseAccount` instructions. Review [security best
              practices](/wallets/gas-and-asset-management/gas/security) before shipping to production.
            </Warning>

            ```bash highlight={9} theme={"system"}
            $ curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/rpc \
              -u "<your-privy-app-id>:<your-privy-app-secret>" \
              -H "privy-app-id: <your-privy-app-id>" \
              -H "privy-authorization-signature: <authorization-signature-for-request>" \
              -H 'Content-Type: application/json' \
              -d '{
                  "method": "signAndSendTransaction",
                  "caip2": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
                  "sponsor": true,
                  "params": {
                      "transaction": "insert-base-64-encoded-serialized-transaction",
                      "encoding": "base64"
                  }
              }'
            ```
          </Tab>

          <Tab title="Solana (Node SDK)">
            <Warning>
              On Solana, sponsored transactions can be abused through ATA rent refunds when
              transactions include `CloseAccount` instructions. Review [security best
              practices](/wallets/gas-and-asset-management/gas/security) before shipping to production.
            </Warning>

            ```typescript highlight={22} theme={"system"}
            import { PrivyClient } from '@privy-io/node';

            const privy = new PrivyClient({ appId: 'your-app-id', appSecret: 'your-app-secret' });

            const response = await privy
              .wallets()
              .solana()
              .signAndSendTransaction(walletId, {
                caip2: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
                transaction,
                sponsor: true,
              });
            ```
          </Tab>
        </Tabs>

        <Info>
          **Using gas sponsorship from other client SDKs**

          The `sponsor: true` parameter is currently supported in the React SDK and server-side
          SDKs (REST API, Node, Rust). For other client SDKs (React Native, Swift, Android,
          Flutter, Unity), you can achieve gas sponsorship by building the transaction in your
          client, then [relaying it through your server](/controls/authorization-keys/keys/create/user/request)
          with `sponsor: true`.
        </Info>
      </Step>
    </Steps>

    <Check>
      On-chain signature verification operations such as Permit2 and TransferWithAuthorization are
      supported for EIP-7702 upgraded wallets via ERC-1271 signing. Learn how to enable this in the
      [ERC-1271 signatures guide](/recipes/evm/erc-1271-signatures).
    </Check>

    ## Next steps

    <CardGroup cols={2}>
      <Card title="Transaction management" icon="clock" href="/wallets/gas-and-asset-management/gas/transaction-handling">
        Learn how gas-sponsored transactions work and how to track transaction status with webhooks
      </Card>

      <Card title="Security best practices" icon="shield-check" href="/wallets/gas-and-asset-management/gas/security">
        Protect your application from gas sponsorship abuse with rate limiting and threat mitigation
        strategies
      </Card>
    </CardGroup>
  </Tab>

  <Tab title="User pays">
    Gas fees are covered using the wallet's stablecoin balance (USDC, USDT, EURC, USDG, or USDC.e
    depending on chain) — no ETH required, and your app's gas credits are not charged.

    <Info>
      User pays mode is currently only supported on EVM chains via the [transfer
      API](/wallets/actions/transfer/overview). It does not apply to raw `eth_sendTransaction` or
      `wallet_sendCalls` RPC calls.
    </Info>

    ## Supported chains and tokens

    | Chain                      | USDC | USDT | EURC | USDG | USDC.e |
    | :------------------------- | :--: | :--: | :--: | :--: | :----: |
    | Ethereum                   |   ✓  |   ✓  |   ✓  |   ✓  |    —   |
    | Base                       |   ✓  |   ✓  |   ✓  |   —  |    —   |
    | Optimism                   |   ✓  |   ✓  |   —  |   —  |    —   |
    | Arbitrum                   |   ✓  |   ✓  |   —  |   —  |    —   |
    | Polygon                    |   ✓  |   ✓  |   —  |   —  |    ✓   |
    | Sepolia (testnet)          |   ✓  |   ✓  |   ✓  |   ✓  |    —   |
    | Base Sepolia (testnet)     |   ✓  |   ✓  |   ✓  |   —  |    —   |
    | OP Sepolia (testnet)       |   ✓  |   —  |   —  |   —  |    —   |
    | Arbitrum Sepolia (testnet) |   ✓  |   —  |   —  |   —  |    —   |
    | Polygon Amoy (testnet)     |   ✓  |   —  |   —  |   —  |    —   |

    ## Getting started

    <Steps>
      <Step title="Enable user pays mode in the dashboard">
        Go to **Wallet Infrastructure → Gas sponsorship** in the [Privy
        Dashboard](https://dashboard.privy.io/apps?page=gas_sponsorship) and select **User pays**.

        <img src="https://mintcdn.com/privy-c2af3412/CHJvYgz8mjsceGUM/images/gas-user-pays.png?fit=max&auto=format&n=CHJvYgz8mjsceGUM&q=85&s=96f44ba282357dca98cec63c38fe259c" alt="Gas management dashboard showing User pays mode selected with custom token rows" width="3686" height="2633" data-path="images/gas-user-pays.png" />
      </Step>

      <Step title="Configure which chains and tokens to accept">
        Under **Custom gas payment tokens**, click **+ Add token** to add one or more chain/token
        pairs. Each row specifies a chain and the token users will pay gas with on that chain.

        Click **Save** when done.

        <Note>
          The token dropdown only shows tokens deployed on the selected chain. If you change the
          chain after selecting a token, the token selection resets automatically.
        </Note>
      </Step>

      <Step title="Ensure wallets hold sufficient balance">
        Before executing a transfer, the user's wallet must hold enough of the configured token to
        cover **both the transfer amount and the gas fee**. Privy estimates the gas fee
        automatically and returns a clear error if the balance is insufficient — the transaction
        will not be submitted.
      </Step>

      <Step title="Execute a transfer">
        Call the [transfer API](/wallets/actions/transfer/overview) as normal — no extra parameters
        are required. When the app is in user pays mode and the source token is configured for that
        chain, Privy automatically uses that token to pay gas.

        ```bash theme={"system"}
        curl --request POST https://api.privy.io/v1/wallets/<wallet_id>/transfer \
          -u "<your-privy-app-id>:<your-privy-app-secret>" \
          -H "privy-app-id: <your-privy-app-id>" \
          -H "privy-authorization-signature: <authorization-signature>" \
          -H 'Content-Type: application/json' \
          -d '{
            "source": {
              "asset": "usdc",
              "amount": "10.0",
              "chain": "base"
            },
            "destination": {
              "address": "0xRecipientAddress"
            }
          }'
        ```

        The gas token is always the same as the token being transferred. For example, when a user
        sends USDC on Base and you have configured Base with USDC, the gas fee is deducted in USDC
        — no ETH is required.
      </Step>
    </Steps>

    ## How it works

    When a qualifying transfer is submitted, Privy:

    1. **Gets a gas quote** from the Alchemy ERC-20 paymaster to estimate the maximum fee
    2. **Checks the wallet balance** — verifies the wallet holds enough to cover both the transfer amount and the estimated gas fee, returning an error immediately if not
    3. **Submits the transaction** — an approval for the paymaster is bundled atomically with the transfer
    4. **Paymaster collects the fee** — after execution, the paymaster collects the exact gas fee from the wallet's configured token balance.

    ## Errors

    | Error                           | Cause                                                                                        |
    | :------------------------------ | :------------------------------------------------------------------------------------------- |
    | `400` — insufficient balance    | The wallet doesn't have enough of the source token to cover both the transfer amount and gas |
    | `400` — unsupported chain/token | The chain or token combination is not supported for token gas (e.g. USDT on OP Sepolia)      |

    ## Gas spend reporting

    Transfers executed in user pays mode are **not included** in your app's gas credit spend
    reported by `GET /v1/apps/gas_spend`. Since the user's tokens cover the fee directly, these
    transactions do not affect your Privy gas credits balance.

    ## Limitations

    * **Transfer API only.** User pays mode is not available for raw RPC methods (`eth_sendTransaction`, `wallet_sendCalls`).
    * **EVM only.** User pays mode is not supported on Solana.
    * **Gas token must match the transfer token.** Gas is always paid using the same token being transferred — you cannot, for example, transfer ETH and pay gas in USDC.
    * **Named assets only.** Only `usdc` and `usdt` are supported as gas payment tokens.
  </Tab>
</Tabs>
