For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at the same URL with .md appended (or via Accept: text/markdown).
Skip to main content

Recurring x402 payments

In this guide, you set up recurring x402 payments by requesting an ERC-20 periodic Advanced PermissionsAdvanced 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

Steps

1. Install the dependencies

npm install @x402/core @x402/fetch @metamask/x402

2. Set up a Wallet Client

Set up a Wallet Client using Viem's createWalletClient function. Use this client to interact with MetaMask.

Extend the Wallet Client with erc7715ProviderActions to enable Advanced PermissionsAdvanced 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())

3. Set up an agent account

The session account can be either a smart accountMetaMask 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 EOAExternally 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...')

4. 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 with a weekly allowance of 10 USDC. This creates a recurring payment budget that your agent can store and reuse for x402 API calls.

See the 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,
},
},
])

5. Create an x402 ERC-7710 client

Create an x402Erc7710Client with a delegationProvider callback. The x402 client calls this function automatically when it needs to pay for a request, passing in the payment requirements from the server.

Inside the provider, create an open redelegationOpen redelegation A redelegation with no specific delegate, allowing any account to redeem inherited permissions. from the agent account so the facilitator can redeem the permission context for x402 settlement. This example uses the erc20TransferAmount scope to allow USDC transfers up to the amount requested in payment terms.

Use the Wallet Client's redelegatePermissionContextOpen action to create a redelegated permission context.

import { ScopeType, CaveatType } from '@metamask/smart-accounts-kit'
import { x402Erc7710Client } from '@metamask/x402'
import { getAddress } from 'viem'
import { environment, sessionAccountWalletClient } from './config'

const permission = grantedPermissions[0]

const erc7710Client = new x402Erc7710Client({
delegationProvider: async requirements => {
const { permissionContext: redelegatedPermissionContext } =
await sessionAccountWalletClient.redelegatePermissionContextOpen({
environment,
permissionContext: permission.context,
scope: {
type: ScopeType.Erc20TransferAmount,
tokenAddress: getAddress(requirements.asset),
maxAmount: BigInt(requirements.amount),
},
})

return {
delegationManager: permission.delegationManager,
permissionContext: redelegatedPermissionContext,
delegator: permission.from,
}
},
})

6. Register the client

Register the ERC-7710 client with the x402 core client for all EVM networks, then create an HTTP client and a payment-aware fetch function using wrapFetchWithPayment.

import { x402Client, x402HTTPClient } from '@x402/core/client'
import { wrapFetchWithPayment } from '@x402/fetch'

const coreClient = new x402Client().register('eip155:*', erc7710Client)
const httpClient = new x402HTTPClient(coreClient)

const fetchWithPayment = wrapFetchWithPayment(fetch, httpClient)

7. Make the paid request

Call the protected endpoint using fetchWithPayment. It handles the x402 payment flow, calling your delegationProvider to create an open redelegation when the server returns a 402 response.

const paidResponse = await fetchWithPayment('https://api.example.com/paid-endpoint', {
method: 'GET',
})

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.