<!--
Sitemap:
- [Tempo Accounts SDK - Getting Started](/docs/): Set up the Tempo Accounts SDK to create, manage, and interact with accounts on Tempo.
- [Deploying to Production](/docs/production): Things to consider before deploying your application with the Tempo Accounts SDK to production.
- [FAQ](/docs/faq): Frequently asked questions about the Tempo Accounts SDK.
- [Connect Accounts](/docs/guides/connect-accounts): Connect a Tempo account in your application.
- [Authentication](/docs/guides/authentication): Authenticate connected accounts against your own server with a signed SIWE challenge.
- [Identity](/docs/guides/identity): Request and verify identity claims about a connected account, starting with a verified email.
- [Transfers](/docs/guides/transfers): Send stablecoin transfers from a connected Tempo account, initiated either by the user or by your server.
- [Spend Permissions](/docs/guides/spend-permissions): Authorize spend limits, call scopes, and expiries so repeat transfers can be signed without a confirmation prompt.
- [React Native](/docs/guides/react-native): Set up Tempo Accounts in a React Native app.
- [Subscriptions](/docs/guides/subscriptions): Charge recurring payments from a connected Tempo account.
- [Fee Sponsorship](/docs/guides/fee-sponsorship): Sponsor transaction fees from a server-controlled policy.
- [Deposits](/docs/guides/deposits): Open the Tempo deposit flow from a connected account and let the user choose deposit details.
- [Swaps](/docs/guides/swaps): Open the Tempo swap flow from a connected account with optional pre-filled intent fields.
- [Theming](/docs/guides/theming): Match embedded account surfaces to your product.
- [CLI](/docs/guides/cli): Authorize and use Tempo accounts from command-line tools.
- [Adapters](/docs/adapters/): Choose the signing adapter for your Tempo Accounts SDK integration.
- [Tempo Wallet Adapter](/docs/adapters/tempo-wallet): Use Tempo Wallet as the hosted universal wallet adapter.
- [WebAuthn Adapter](/docs/adapters/webauthn): Use domain-bound passkeys as the account signing adapter.
- [Turnkey Adapter](/docs/adapters/turnkey): Use Turnkey-managed wallet accounts as the account signing adapter.
- [Privy Adapter](/docs/adapters/privy): Use Privy embedded wallets as the account signing adapter.
- [Private Key Adapter](/docs/adapters/private-key): Sign in-process with a `secp256k1` private key.
- [Custom Adapter](/docs/adapters/custom): Author your own adapter with the `Adapter.define` API.
- [Adapters](/docs/api/adapters): Pluggable adapters for the Tempo Accounts SDK Provider.
- [dialog](/docs/api/dialog): Adapter for the Tempo Wallet dialog, an embedded iframe or popup for account management.
- [local](/docs/api/local): Key-agnostic adapter for defining arbitrary account types and signing mechanisms.
- [mobileWebAuth](/docs/api/mobileWebAuth): Mobile web auth adapter for browser-session wallet requests.
- [postMessage](/docs/api/postMessage): Connect to wallet from anywhere on the web
- [privy](/docs/api/privy): React adapter backed by Privy sessions and embedded Ethereum wallets.
- [secp256k1](/docs/api/secp256k1): Adapter that signs in-process with a `secp256k1` private key.
- [turnkey](/docs/api/turnkey): Adapter backed by Turnkey client sessions.
- [webAuthn](/docs/api/webAuthn): Adapter for passkey-based accounts using WebAuthn registration and authentication.
- [Dialog](/docs/api/dialogs): Dialog modes for embedding the Tempo Wallet.
- [Dialog.iframe](/docs/api/dialog.iframe): Embed the Tempo Wallet auth UI in an iframe dialog element.
- [Dialog.popup](/docs/api/dialog.popup): Open the Tempo Wallet auth UI in a popup window.
- [Expiry](/docs/api/expiry): Utility functions for computing access key expiry timestamps.
- [Provider](/docs/api/provider): Create an EIP-1193 provider for managing accounts on Tempo.
- [Rpc](/docs/api/rpc): Per-method Zod schemas and shared building blocks for the Accounts JSON-RPC surface.
- [Schema](/docs/api/schema): Zod-based JSON-RPC schema definitions for the Accounts provider.
- [TrustedHosts](/docs/api/trustedHosts): Trusted host mappings and matching helpers for dialog adapters.
- [WebAuthnCeremony](/docs/api/webauthnceremony): Pluggable strategy for WebAuthn registration and authentication ceremonies.
- [WebAuthnCeremony.from](/docs/api/webauthnceremony.from): Create a WebAuthnCeremony from a custom implementation.
- [WebAuthnCeremony.server](/docs/api/webauthnceremony.server): Server-backed WebAuthn ceremony that delegates to a remote handler.
- [CLI](/docs/cli/provider): Create a Provider for CLI environments.
- [eth_accounts](/docs/rpc/eth_accounts): Get the addresses of the currently connected accounts.
- [eth_chainId](/docs/rpc/eth_chainId): Get the chain ID of the currently active chain.
- [eth_fillTransaction](/docs/rpc/eth_fillTransaction): Fills missing transaction fields and returns wallet-aware metadata.
- [eth_requestAccounts](/docs/rpc/eth_requestAccounts): Request access to user accounts, prompting the user to connect if needed.
- [eth_sendTransaction](/docs/rpc/eth_sendTransaction): Send a transaction from the connected account.
- [eth_sendTransactionSync](/docs/rpc/eth_sendTransactionSync): Send a transaction and wait for the receipt.
- [eth_signTransaction](/docs/rpc/eth_signTransaction): Sign a transaction without broadcasting it.
- [eth_signTypedData_v4](/docs/rpc/eth_signTypedData_v4): Sign EIP-712 typed structured data with the connected account.
- [personal_sign](/docs/rpc/personal_sign): Sign a message with the connected account.
- [wallet_authorizeAccessKey](/docs/rpc/wallet_authorizeAccessKey): Authorize an access key for delegated transaction signing.
- [wallet_authorizeChallenge](/docs/rpc/wallet_authorizeChallenge): Authorize Machine Payment Protocol (MPP) challenges.
- [wallet_connect](/docs/rpc/wallet_connect): Connect account(s) with optional capabilities like access key authorization.
- [wallet_deposit](/docs/rpc/wallet_deposit): Open the wallet deposit flow with optional pre-filled fields.
- [wallet_depositZone](/docs/rpc/wallet_depositZone): Open the wallet zone-deposit flow with optional pre-filled fields.
- [wallet_disconnect](/docs/rpc/wallet_disconnect): Disconnect the connected account(s).
- [wallet_getBalances](/docs/rpc/wallet_getBalances): Get token balances for an account.
- [wallet_getCallsStatus](/docs/rpc/wallet_getCallsStatus): Get the status of a batch of calls sent via wallet_sendCalls.
- [wallet_getCapabilities](/docs/rpc/wallet_getCapabilities): Get account capabilities for specified chains.
- [wallet_revokeAccessKey](/docs/rpc/wallet_revokeAccessKey): Revoke a previously authorized access key.
- [wallet_send](/docs/rpc/wallet_send): Open the wallet send-token flow with optional pre-filled fields.
- [wallet_sendCalls](/docs/rpc/wallet_sendCalls): Send a batch of calls from the connected account.
- [wallet_swap](/docs/rpc/wallet_swap): Open the wallet swap flow with optional pre-filled swap intent fields.
- [wallet_switchEthereumChain](/docs/rpc/wallet_switchEthereumChain): Switch the provider's active chain.
- [wallet_withdrawZone](/docs/rpc/wallet_withdrawZone): Open the wallet zone-withdraw flow with optional pre-filled fields.
- [Remote](/docs/api/remote): Bridge that runs inside the wallet's iframe/popup and serves RPC requests from the host SDK.
- [Remote.create](/docs/api/remote.create): Create a remote context bound to a Messenger and Provider.
- [Remote.useEnsureVisibility](/docs/api/remote.useEnsureVisibility): React hook that monitors iframe visibility and falls back to a popup when occluded.
- [Remote.useState](/docs/api/remote.useState): React hook to subscribe to a remote context's state store.
- [Remote.useTheme](/docs/api/remote.useTheme): React hook that applies theme overrides from URL search params and live messenger updates.
- [Remote.validateSearch](/docs/api/remote.validateSearch): Validate an RPC request payload from URL search params.
- [Tempo Accounts Server Handlers](/docs/server/): Configure server-side Tempo Accounts SDK handlers for relaying wallet RPC requests, composing backends, and managing WebAuthn ceremonies.
- [Handler.auth](/docs/server/handler.auth): Server handler that issues SIWE-based authentication challenges and sessions.
- [Handler.codeAuth](/docs/server/handler.codeAuth): Server handler for the device-code (PKCE) access-key bootstrap flow.
- [Handler.compose](/docs/server/handler.compose): Compose multiple server handlers into a single handler.
- [Handler.exchange](/docs/server/handler.exchange): Server handler that returns Stablecoin DEX quotes and ready-to-submit calls.
- [Handler.relay](/docs/server/handler.relay): Server handler that proxies certain RPC requests with wallet-aware enrichment.
- [Handler.webAuthn](/docs/server/handler.webAuthn): Server-side WebAuthn ceremony handler for registration and authentication.
- [hc](/docs/server/hc): Typed RPC client for handlers built with the Tempo Accounts SDK.
- [Identity.verify](/docs/server/identity.verify): Verify a wallet-issued identity token (verified email) against an issuer's JWKS.
- [Kv](/docs/server/kv): Key-value store adapters for server-side persistence.
- [Kv.cloudflare](/docs/server/kv.cloudflare): Kv adapter backed by a Cloudflare Workers KV namespace.
- [Kv.durableObject](/docs/server/kv.durableObject): Kv adapter backed by a Cloudflare Durable Object with atomic take and create.
- [Kv.from](/docs/server/kv.from): Wrap a custom Kv-shaped object so the SDK accepts it as a Kv.
- [Kv.memory](/docs/server/kv.memory): In-memory Kv adapter for tests and single-process deployments.
- [Keystore](/docs/api/keystore): Pluggable backends for key material.
- [Keystore.p256](/docs/api/keystore.p256): Pure-JS P-256 keystore.
- [Keystore.secp256k1](/docs/api/keystore.secp256k1): Pure-JS secp256k1 keystore.
- [Keystore.webCryptoP256](/docs/api/keystore.webCryptoP256): WebCrypto P-256 keystore.
- [Storage](/docs/api/storage): Pluggable storage adapters for persisting provider state.
- [Storage.combine](/docs/api/storage.combine): Combine multiple Storage adapters into one.
- [Storage.cookie](/docs/api/storage.cookie): Cookie-backed Storage adapter.
- [Storage.from](/docs/api/storage.from): Create a Storage adapter from a custom implementation.
- [Storage.idb](/docs/api/storage.idb): IndexedDB-backed Storage adapter.
- [Storage.localStorage](/docs/api/storage.localStorage): localStorage-backed Storage adapter.
- [Storage.memory](/docs/api/storage.memory): In-memory Storage adapter.
- [asyncStorage](/docs/api/storage.asyncStorage): React Native Storage adapter backed by AsyncStorage.
- [secureMmkv](/docs/api/storage.secureMmkv): Encrypted React Native Storage adapter backed by MMKV.
- [Tempo Accounts SDK](/index): The fastest way to add stablecoins to your application.
- [Secp256k1 Adapter](/docs/adapters/secp256k1): Sign in-process with a `secp256k1` private key.
- [Bring Your Auth](/docs/enterprise/bring-your-auth/): Connect enterprise auth and signing systems to Tempo accounts.
- [Hosted Universal Wallets](/docs/enterprise/hosted-universal-wallets): Stub for hosting a universal wallet on your own domain.
- [Handler.feePayer (Deprecated)](/docs/server/handler.feePayer): Deprecated — use Handler.relay with feePayer option instead.
- [tempoWallet](/docs/wagmi/tempoWallet): Wagmi connector for the Tempo Wallet dialog.
- [webAuthn](/docs/wagmi/webAuthn): Wagmi connector for passkey-based WebAuthn accounts.
- [AWS KMS](/docs/enterprise/bring-your-auth/aws-kms): Stub for integrating AWS KMS-backed signing with the Tempo Accounts SDK.
- [Custom Auth](/docs/enterprise/bring-your-auth/custom): Stub for first-party enterprise auth and signing integrations.
- [Privy](/docs/enterprise/bring-your-auth/privy): Enterprise notes for integrating Privy-backed auth with the Tempo Accounts SDK.
- [Turnkey](/docs/enterprise/bring-your-auth/turnkey): Stub for integrating Turnkey-backed signing with the Tempo Accounts SDK.
-->

# Fee Sponsorship

Let connected accounts complete approved actions without keeping fee tokens on hand. Your app decides which transactions qualify for sponsorship, pays the network fee for those requests, and leaves every other transaction on the normal self-funded path.

## Demo

By the end of this guide you'll have a fee sponsorship flow where the user signs in, your server decides whether to sponsor a request, and matching transfers can be routed through the server-owned fee payer.

<Demo title="Sponsored Transfer" githubUrl="https://github.com/tempoxyz/accounts/tree/main/examples/fee-payer" wagmiConfig="feeSponsorship" headerAction={<DemoReset />} className="flex flex-col gap-3">
  <Steps.Step label="Create an account, or use an existing one." action={<ConnectAccount />} />

  <SponsoredPayment value={2} />
</Demo>

## Walkthrough

::::steps

### Connect an Account

Follow the [Connect Accounts](/docs/guides/connect-accounts) guide to set up Wagmi with Tempo Wallet, WebAuthn, or another signing adapter. Fee sponsorship works after the user has a connected account that can sign the transaction.

### Install the Server Dependencies

Install [Hono](https://hono.dev) for the server snippets in this guide.

:::code-group

```bash [npm]
npm i hono
```

```bash [pnpm]
pnpm i hono
```

```bash [bun]
bun i hono
```

:::

:::tip\[Any framework works]
`Handler.relay` supports the Web Fetch API and Node.js `RequestListener`, so you can mount it in Hono, Express, Next.js, Bun, Deno, Elysia, or another server framework.
:::

### Mount the Relay

Create a [`Handler.relay`](/docs/server/handler.relay) with a `feePayer` account and expose it under `/relay`. The relay fills incoming transactions, signs the fee payer portion when sponsorship is approved, and returns a transaction that the connected account can sign.

```ts twoslash [worker/index.ts]
// @noErrors
import { Handler } from 'accounts/server'
import { Hono } from 'hono'
import { privateKeyToAccount } from 'viem/accounts'

const app = new Hono()
const relay = Handler.relay({
  feePayer: {
    account: privateKeyToAccount(process.env.RELAY_PRIVATE_KEY),
    name: 'My App',
    url: 'https://myapp.com',
  },
  path: '/relay',
})

app.all('/relay/*', (c) => relay.fetch(c.req.raw))

export default app
```

:::tip\[Using a different framework?]
`Handler.relay` exposes both `fetch` (Web Fetch API) and `listener` (Node.js `RequestListener`) entrypoints, so you can plug the same relay into any server framework:

```ts
createServer(relay.listener)               // Node.js
Bun.serve({ fetch: relay.fetch })          // Bun
Deno.serve({ fetch: relay.fetch })         // Deno
app.all('*', c => relay.fetch(c.request))  // Elysia
app.use(relay.listener)                    // Express
app.use(c => relay.fetch(c.req.raw))       // Hono
export const GET = relay.fetch             // Next.js
export const POST = relay.fetch            // Next.js
```

:::

:::warning\[Add a sponsorship policy]
The minimal example sponsors any transaction sent to the relay. Before funding a production fee payer account, add `feePayer.validate`, rate limits, and logging so your server only sponsors the requests your app intends to support.
:::

### Configure the Connector

Pass the relay URL to your connector with `feePayer`. This tells Tempo Wallet which app relay should sponsor the transaction when signing locally or falling back to the hosted wallet UI.

:::code-group

```tsx twoslash [Tempo Wallet]
// @noErrors
import { createConfig, http } from 'wagmi'
import { tempo, tempoModerato } from 'wagmi/chains'
import { tempoWallet } from 'wagmi/connectors'

export const config = createConfig({
  chains: [tempo, tempoModerato],
  connectors: [
    tempoWallet({
      testnet: true,
      feePayer: import.meta.env.VITE_FEE_PAYER_URL ?? '/relay', // [!code focus]
    }),
  ],
  multiInjectedProviderDiscovery: false,
  transports: {
    [tempo.id]: http(),
    [tempoModerato.id]: http(),
  },
})
```

```tsx twoslash [Domain-bound Passkeys]
// @noErrors
import { createConfig, http } from 'wagmi'
import { tempo, tempoModerato } from 'wagmi/chains'
import { webAuthn } from 'wagmi/tempo'

export const config = createConfig({
  chains: [tempo, tempoModerato],
  connectors: [
    webAuthn({
      testnet: true,
      authUrl: '/auth',
      feePayer: '/relay', // [!code focus]
    }),
  ],
  multiInjectedProviderDiscovery: false,
  transports: {
    [tempo.id]: http(),
    [tempoModerato.id]: http(),
  },
})
```

:::

### Send a Transfer

Call [`Hooks.wallet.useTransfer`](https://wagmi.sh/tempo/hooks/wallet.useTransfer) normally. With `feePayer` configured, the transfer uses your relay by default, where the server decides whether to sponsor it.

```tsx twoslash [Transfer.tsx]
// @noErrors
import { Hooks } from 'wagmi/tempo'

export function Transfer() {
  const transfer = Hooks.wallet.useTransfer()

  return (
    <button
      disabled={transfer.isPending}
      onClick={() =>
        transfer.mutate({
          amount: '1',
          to: '0x0000000000000000000000000000000000000001',
          token: 'pathusd',
        })
      }
    >
      {transfer.isPending ? 'Sending...' : 'Pay $1'}
    </button>
  )
}
```

### Show the Fee Payer

The transfer result includes the submitted receipt. When sponsorship succeeds, `receipt.feePayer` is the server-owned account that paid the transaction fee.

```tsx twoslash [Transfer.tsx]
// @noErrors
import { Hooks } from 'wagmi/tempo'

export function Transfer() {
  const transfer = Hooks.wallet.useTransfer()

  return (
    <div>
      <button onClick={() => transfer.mutate({ /* ... */ })}>Pay $1</button>
      {transfer.data?.receipt.feePayer && (
        <p>
          Fees paid by <code>{transfer.data.receipt.feePayer}</code>
        </p>
      )}
    </div>
  )
}
```

:::tip\[Per-request control]
The transfer above does not pass a `feePayer` override. The connector-level `feePayer` value is used by default. Only pass `feePayer: false` when you intentionally want the connected account to pay its own transaction fee.
:::

::::

## Best Practices

### Validate Sponsorship Server-Side

Treat the relay as the policy boundary. Use `feePayer.validate` to check the account, target contracts, calldata, token amounts, and any app-level limits before signing. Returning `false` does not reject the transaction outright — the relay re-fills it for self-payment.

```ts twoslash [worker/index.ts]
// @noErrors
import { Handler } from 'accounts/server'
import { privateKeyToAccount } from 'viem/accounts'

const blocked = '0x0000000000000000000000000000000000000001'

const handler = Handler.relay({
  feePayer: {
    account: privateKeyToAccount('0x...'),
    validate: (request) =>
      request.from?.toLowerCase() !== blocked.toLowerCase(), // [!code focus]
  },
})
```

## Next Steps

<Cards>
  <Card description="Run the Tempo Wallet fee sponsorship example locally." to="https://github.com/tempoxyz/accounts/tree/main/examples/fee-payer" icon="lucide:badge-dollar-sign" title="Fee Payer Example" />

  <Card description="Configure the relay that fills, validates, and signs sponsored transactions." to="/docs/server/handler.relay" icon="lucide:hand-coins" title="Handler.relay" />

  <Card description="Send stablecoin transfers from a connected account." to="/docs/guides/transfers" icon="lucide:send" title="Transfers" />

  <Card description="Configure Tempo Wallet with auth, access keys, and fee sponsorship." to="/docs/wagmi/tempoWallet" icon="lucide:wallet" title="Tempo Wallet" />
</Cards>
