Pay for an x402 API with delegation
In this guide, you use a buyer account to access API data from an x402 server by creating an open delegation that authorizes token transfers on your behalf.
You set up an x402Erc7710Client with a delegation provider, register it with the x402 client,
and use wrapFetchWithPayment to automatically handle payment when calling a protected API route.
Prerequisites
Steps
1. Install the dependencies
- npm
- Yarn
- pnpm
- Bun
npm install @x402/core @x402/fetch @metamask/x402
yarn add @x402/core @x402/fetch @metamask/x402
pnpm add @x402/core @x402/fetch @metamask/x402
bun add @x402/core @x402/fetch @metamask/x402
2. Create a buyer account
Create an account to represent the buyer, the delegatorDelegator account The account that creates and signs a delegation to grant limited authority to another account. who creates a delegation.
The delegator must be a MetaMask 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..
Use the toolkit's
toMetaMaskSmartAccount method to
create the buyer account.
Fund the smart account with USDC for the requested payment.
- example.ts
- config.ts
import { Implementation, toMetaMaskSmartAccount } from '@metamask/smart-accounts-kit'
import { publicClient, buyerAccount } from './config'
export const buyerSmartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [buyerAccount.address, [], [], []],
deploySalt: '0x',
signer: { account: buyerAccount },
})
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base as chain } from 'viem/chains'
export const publicClient = createPublicClient({
chain,
transport: http(),
})
export const buyerAccount = privateKeyToAccount('0x<BUYER_PRIVATE_KEY>')
3. 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 delegation
using createOpenDelegation.
This example uses the erc20TransferAmount
scope to allow USDC transfers up to the requested amount, and the
timestamp caveat to set a short expiry.
For ERC-7710, x402 requires the payload fields delegationManager, permissionContext, and delegator.
Use encodeDelegations to encode the delegation chain.
import { CaveatType, createOpenDelegation, ScopeType } from '@metamask/smart-accounts-kit'
import { encodeDelegations } from '@metamask/smart-accounts-kit/utils'
import { x402Erc7710Client } from '@metamask/x402'
import { getAddress } from 'viem'
const erc7710Client = new x402Erc7710Client({
delegationProvider: async requirements => {
// Expires in 1 minute.
const expiry = Math.floor(Date.now() / 1000) + 60
const delegation = createOpenDelegation({
environment: buyerSmartAccount.environment,
from: buyerSmartAccount.address,
scope: {
type: ScopeType.Erc20TransferAmount,
tokenAddress: getAddress(requirements.asset),
maxAmount: BigInt(requirements.amount),
},
caveats: [
{
type: CaveatType.Timestamp,
afterThreshold: 0,
beforeThreshold: expiry,
},
],
})
const signature = await buyerSmartAccount.signDelegation({
delegation,
})
const signedDelegation = {
...delegation,
signature,
}
return {
delegationManager: buyerSmartAccount.environment.DelegationManager,
permissionContext: encodeDelegations([signedDelegation]),
delegator: buyerSmartAccount.address,
}
},
})
4. Register the client
Register the ERC-7710 client with the x402 core client for all EVM networks.
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)
5. 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',
})