- App pays
- User pays
Your app’s gas credits cover transaction fees for all users. Users transact without ever needing
to hold ETH or native tokens.
Before enabling gas sponsorship in production, review the security best
practices to help prevent abuse and protect gas
balances.
Getting started
1
Enable gas sponsorship in the dashboard
Go to the gas sponsorship tab in the Privy
Dashboard and select App pays.
2
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!
3
Send transaction requests
Apps must use TEE execution in order
to use our native gas sponsorship feature. Learn how to migrate
here!
- Ethereum (React)
- Tempo (React)
- Solana (React)
- Ethereum (REST API)
- Tempo (REST API)
- Ethereum (Node SDK)
- Tempo (Node SDK)
- Solana (REST API)
- Solana (Node SDK)
With the React SDK, use the
useSendTransaction hook with sponsor: true:import {useSendTransaction, useWallets} from '@privy-io/react-auth';
const {sendTransaction} = useSendTransaction();
const {wallets} = useWallets();
sendTransaction(
{
to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
value: 100000
},
{
sponsor: true // Enable gas sponsorship
}
);
With the React SDK, use the Tempo
useSendTransaction hook with sponsor: true: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
}
);
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.With the React SDK, use the
useSignAndSendTransaction hook with sponsor: true:On Solana, sponsored transactions can be abused through ATA rent refunds when
transactions include
CloseAccount instructions. Review security best
practices before shipping to production.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
}
});
Allow transactions from the clientTo 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.
$ 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"
}
}
}'
To sponsor transactions initiated from a client SDK, you may relay the
transaction from your server.
$ 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"
}
]
}
}
}'
Passing
sponsor: true makes Privy populate the Tempo fee_payer_signature before
broadcasting the transaction.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,
});
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,
});
On Solana, sponsored transactions can be abused through ATA rent refunds when
transactions include
CloseAccount instructions. Review security best
practices before shipping to production.$ 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"
}
}'
On Solana, sponsored transactions can be abused through ATA rent refunds when
transactions include
CloseAccount instructions. Review security best
practices before shipping to production.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,
});
Using gas sponsorship from other client SDKsThe
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
with sponsor: true.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.
Next steps
Transaction management
Learn how gas-sponsored transactions work and how to track transaction status with webhooks
Security best practices
Protect your application from gas sponsorship abuse with rate limiting and threat mitigation
strategies
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.User pays mode works with the transfer API,
eth_sendTransaction, and
wallet_sendCalls.
Tempo also accepts PathUSD and USDT0. On Tempo, user pays mode is supported through the transfer
API only.
User pays mode is EVM only. It is not supported on Solana.
Supported chains and tokens
| Chain | USDC | USDT | EURC | USDG | USDC.e |
|---|---|---|---|---|---|
| Ethereum | ✓ | ✓ | ✓ | ✓ | — |
| Base | ✓ | ✓ | ✓ | — | — |
| Tempo | — | — | — | — | ✓ |
| Optimism | ✓ | ✓ | — | — | — |
| Arbitrum | ✓ | ✓ | — | — | — |
| Polygon | ✓ | ✓ | — | — | ✓ |
| Sepolia (testnet) | ✓ | ✓ | ✓ | ✓ | — |
| Base Sepolia (testnet) | ✓ | ✓ | ✓ | — | — |
| OP Sepolia (testnet) | ✓ | — | — | — | — |
| Arbitrum Sepolia (testnet) | ✓ | — | — | — | — |
| Polygon Amoy (testnet) | ✓ | — | — | — | — |
Getting started
1
Enable user pays mode in the dashboard
Go to Wallet Infrastructure → Gas sponsorship in the Privy
Dashboard and select User pays.
2
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.
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.
3
Ensure wallets hold sufficient balance
Before executing a transaction, the user’s wallet must hold enough of the configured token to
cover both the transaction 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.
4
Execute a transaction
- Transfer API
- eth_sendTransaction
- wallet_sendCalls
Call the transfer API 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.On the transfer API, 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.
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"
}
}'
Pass The response returns a
sponsor: true along with sponsor_options.asset to name the token the wallet pays
gas with. Unlike the transfer API, the gas token is chosen explicitly and does not need
to relate to what the transaction does.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>" \
-H 'Content-Type: application/json' \
-d '{
"method": "eth_sendTransaction",
"caip2": "eip155:8453",
"sponsor": true,
"sponsor_options": {
"asset": "usdc"
},
"params": {
"transaction": {
"to": "0xRecipientAddress",
"value": "0x0",
"data": "0x"
}
}
}'
user_operation_hash immediately. The hash field is an empty
string until the user operation confirms on-chain.Batched calls follow the same pattern — add The response returns a
sponsor: true and sponsor_options. The
paymaster approval is bundled atomically with your calls.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>" \
-H 'Content-Type: application/json' \
-d '{
"method": "wallet_sendCalls",
"caip2": "eip155:8453",
"sponsor": true,
"sponsor_options": {
"asset": "usdc"
},
"params": {
"calls": [
{"to": "0xTokenAddress", "data": "0x..."},
{"to": "0xContractAddress", "data": "0x..."}
]
}
}'
transaction_id you can use to track the batch.sponsor_options is supported on the REST API and server-side SDKs. Client SDKs do not
expose it yet — build the transaction in your client, then relay it through your
server.How it works
When a qualifying transaction is submitted, Privy:- Gets a gas quote from the Alchemy ERC-20 paymaster to estimate the maximum fee
- Checks the wallet balance — verifies the wallet holds enough to cover both the transaction amount and the estimated gas fee, returning an error immediately if not
- Submits the transaction — an approval for the paymaster is bundled atomically with the call or calls, as an ERC-4337 user operation
- 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 token to cover both the transaction amount and gas |
400 — unsupported chain/token | The chain or token combination is not supported for token gas (e.g. USDT on OP Sepolia) |
400 — asset not configured | The asset in sponsor_options is not enabled for that chain in the dashboard |
400 — sponsor_options required | The app is in user pays mode but the RPC request passed sponsor: true without sponsor_options |
400 — unsupported method | sponsor_options was passed on a method other than eth_sendTransaction or wallet_sendCalls |
Gas spend reporting
Transactions executed in user pays mode are not included in your app’s gas credit spend reported byGET /v1/apps/gas_spend. Since the user’s tokens cover the fee directly, these
transactions do not affect your Privy gas credits balance.Limitations
- EVM only. User pays mode is not supported on Solana.
- Tempo is transfer API only. RPC requests for Tempo reject
sponsor_options— use the transfer API instead. - Transfer API pays gas in the transferred token. Gas is always paid using the same token being transferred — you cannot, for example, transfer ETH and pay gas in USDC. On the RPC endpoint, you choose the gas token explicitly.
- Named assets only. Transfers must specify
source.asset. Transfers identified bysource.asset_addressdo not qualify for user pays gas. - No contract deployment.
eth_sendTransactionrequests must include atoaddress. - Server-side only.
sponsor_optionsis not yet available in the client SDKs.

