> For the complete documentation index, see [llms.txt](/llms.txt).

# Recurring x402 payments

In this guide, you set up recurring x402 payments by requesting an ERC-20 periodic [Advanced Permissions](/smart-accounts-kit/development/reference/glossary#advanced-permissions)**Advanced Permissions** Fine-grained, wallet execution permissions that dapps can request from MetaMask extension users. Based on ERC-7715. permission from a user.

For example, a user gives your agent permission to spend up to 10 USDC per week. Later, when the agent calls an x402 endpoint, it checks the price, uses the granted permission, and pays.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

- [Install and set up the Smart Accounts Kit.](/smart-accounts-kit/get-started/install/)

## Steps[​](#steps "Direct link to Steps")

### 1\. Set up a Wallet Client[​](#1-set-up-a-wallet-client "Direct link to 1. Set up a Wallet Client")

Set up a Wallet Client using Viem's [createWalletClient](https://viem.sh/docs/clients/wallet) function. Use this client to interact with MetaMask.

Extend the Wallet Client with `erc7715ProviderActions` to enable [Advanced Permissions](/smart-accounts-kit/development/reference/glossary#advanced-permissions)**Advanced Permissions** Fine-grained, wallet execution permissions that dapps can request from MetaMask extension users. Based on ERC-7715. requests.

```
import { createWalletClient, custom } from 'viem'
import { erc7715ProviderActions } from '@metamask/smart-accounts-kit/actions'

const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())

```

### 2\. Set up an agent account[​](#2-set-up-an-agent-account "Direct link to 2. Set up an agent account")

The session account can be either a [smart account](/smart-accounts-kit/development/reference/glossary#metamask-smart-account)**MetaMask smart account** A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations. or an [EOA](/smart-accounts-kit/development/reference/glossary#externally-owned-account-eoa)**Externally owned account (EOA)** A private-key-controlled account with no built-in programmable execution logic.. This example uses an EOA as the session account.

```
import { privateKeyToAccount } from 'viem/accounts'

const sessionAccount = privateKeyToAccount('0x...')

```

### 3\. Request Advanced Permissions[​](#3-request-advanced-permissions "Direct link to 3. Request Advanced Permissions")

Request Advanced Permissions from the user with the Wallet Client's `requestExecutionPermissions` action.

In this example, you request an [ERC-20 periodic permission](/smart-accounts-kit/guides/advanced-permissions/use-permissions/erc20-token/#erc-20-periodic-permission) with a weekly allowance of 10 USDC. This creates a recurring payment budget that your agent can store and reuse for making an x402 API call.

See the [requestExecutionPermissions](/smart-accounts-kit/reference/advanced-permissions/wallet-client/#requestexecutionpermissions) API reference for more information.

```
import { base as chain } from 'viem/chains'
import { parseUnits } from 'viem'

// USDC address on Base.
const tokenAddress = '0x...'

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 60 * 60 * 24 * 30 // Permission expires in 30 days.

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress,
        periodAmount: parseUnits('10', 6),
        periodDuration: 604800,
        startTime: currentTime,
        justification:
          'Permission for agent to spend up to 10 USDC every week for making x402 API calls',
      },
      isAdjustmentAllowed: false,
    },
  },
])

```

### 4\. Get payment requirements[​](#4-get-payment-requirements "Direct link to 4. Get payment requirements")

Call the x402-protected endpoint without the `PAYMENT-SIGNATURE` header to request payment terms after your agent has been granted permission.

The server returns `402` with the payment terms (`PAYMENT-REQUIRED`) in the response, which agent can use to build the payment payload.

```
import { PaymentRequirements } from './types'

// Update the URL
const challengeResponse = await fetch('https://api.example.com/paid-endpoint')
if (challengeResponse.status !== 402) {
  console.error('Expected 402 challenge from protected route')
  // Handle error
}

const paymentRequiredHeader = challengeResponse.headers.get('PAYMENT-REQUIRED')
if (!paymentRequiredHeader) {
  console.error('PAYMENT-REQUIRED header is missing')
  // Handle error
}

const decodedPaymentRequired = Buffer.from(paymentRequiredHeader, 'base64').toString('utf-8')
const paymentRequired = JSON.parse(decodedPaymentRequired) as {
  accepts: PaymentRequirements[]
}

const accepted = paymentRequired.accepts[0]
if (!accepted) {
  console.error('Server did not provide accepted payment requirements')
  // Handle error
}

if (accepted.extra.assetTransferMethod !== 'erc7710') {
  console.error('Server does not support ERC-7710 delegation payments')
  // Handle error
}

if (accepted.asset.toLowerCase() !== tokenAddress.toLowerCase()) {
  console.error('Requested payment asset does not match recurring payment token')
  // Handle error
}

```

### 5\. Create a redelegation[​](#5-create-a-redelegation "Direct link to 5. Create a redelegation")

The granted advanced permission is delegated to the agent account. For each protected API call, create a redelegation from the agent account so facilitator addresses can redeem the permission context for x402 settlement.

This example uses the [erc20TransferAmount](/smart-accounts-kit/guides/delegation/use-delegation-scopes/spending-limit/#erc-20-transfer-scope)scope while creating redelegation to allow USDC transfers up to the amount requested in payment terms. It also uses the [redeemer](/smart-accounts-kit/reference/delegation/caveats/#redeemer) enforcer to restrict redemption to facilitator addresses provided by the server.

Use the Wallet Client's [redelegatePermissionContext](/smart-accounts-kit/reference/erc7710/wallet-client/#redelegatepermissioncontextopen) action to create a redelegated permission context.

- example.ts
- config.ts

```
import { environment, sessionAccountWalletClient } from './config.ts'
import { ScopeType, CaveatType } from '@metamask/smart-accounts-kit'

const permission = grantedPermissions[0]
if (!permission) {
  console.error('No permission response returned by requestExecutionPermissions')
  // Handle error
}

const facilitators = accepted.extra.facilitators
if (!facilitators || facilitators.length === 0) {
  console.error('No facilitators found in payment terms')
  // Handle error
}

const { permissionContext: redelegatedPermissionContext } =
  await sessionAccountWalletClient.redelegatePermissionContext({
    environment,
    permissionContext: permission.context,
    scope: {
      type: ScopeType.Erc20TransferAmount,
      tokenAddress: accepted.asset,
      maxAmount: BigInt(accepted.amount),
    },
    caveats: [
      {
        type: CaveatType.Redeemer,
        redeemers: facilitators,
      },
    ],
  })

```

```
import { createWalletClient, http } from 'viem'
import { base as chain } from 'viem/chains'
import { getSmartAccountsEnvironment } from '@metamask/smart-accounts-kit'
import { erc7710WalletActions } from '@metamask/smart-accounts-kit/actions'

export const environment = getSmartAccountsEnvironment(chain.id)

// Use sessionAccount from previous step
export const sessionAccountWalletClient = createWalletClient({
  account: sessionAccount,
  chain,
  transport: http(),
}).extend(erc7710WalletActions())

```

### 6\. Create the payment payload[​](#6-create-the-payment-payload "Direct link to 6. Create the payment payload")

For each protected API call, create a payment payload with the redelegated permission context.

For ERC-7710 (Smart Contract Delegation), x402 requires the payload fields `delegationManager`, `permissionContext`, and `delegator`. The facilitator uses `permissionContext` to simulate during verification and then settle the payment.

Encode the full x402 payment payload as base64, then send it in the `PAYMENT-SIGNATURE` header.

```
import { PaymentPayload } from './types'

const permission = grantedPermissions[0]

const paymentPayload: PaymentPayload = {
  x402Version: 2,
  accepted,
  payload: {
    delegationManager: permission.delegationManager,
    permissionContext: redelegatedPermissionContext,
    delegator: permission.from,
  },
}

const encodedPayment = Buffer.from(JSON.stringify(paymentPayload)).toString('base64')

```

### 7\. Make the paid request[​](#7-make-the-paid-request "Direct link to 7. Make the paid request")

Send the base64-encoded x402 payment payload in the `PAYMENT-SIGNATURE` header.

```
const apiResponse = await fetch('https://api.example.com/paid-endpoint', {
  headers: {
    'PAYMENT-SIGNATURE': encodedPayment,
  },
})

if (!apiResponse.ok) {
  const errorBody = await apiResponse.json()
  console.error(errorBody.error ?? 'API request failed')
  // Handle error
}

const data = await apiResponse.json()
console.log('Protected API response:', data)

```

Reuse the same weekly granted permission for additional protected routes and providers in your agent flow. Your agent can continue paying until the weekly cap is reached, then continue after the next weekly period starts.
