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

# Pay for an x402 API with delegation

In this guide, you use a buyer [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.to access API data from an x402 server.

You create an open delegation, restrict redemption to the facilitator, encode the delegation chain, and send it as the payment payload when calling a protected API route.

## 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\. Create a buyer account[​](#1-create-a-buyer-account "Direct link to 1. Create a buyer account")

Create an account to represent the buyer, the [delegator](/smart-accounts-kit/development/reference/glossary#delegator-account)**Delegator account** The account that creates and signs a delegation to grant limited authority to another account. who will create a delegation.

The delegator must be a [MetaMask 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.; use the toolkit's [toMetaMaskSmartAccount](/smart-accounts-kit/reference/smart-account/#tometamasksmartaccount) method to create the buyer account.

Important

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>')

```

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

Call the protected API route once without the `PAYMENT-SIGNATURE` header.

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

- example.ts
- types.ts

```
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
}

```

```
export type PaymentRequirements = {
  scheme: string
  network: string
  amount: string
  asset: `0x${string}`
  payTo: `0x${string}`
  maxTimeoutSeconds: number
  extra: {
    assetTransferMethod: string
    facilitators?: `0x${string}`[]
  }
}

```

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

Create an [open root delegation](/smart-accounts-kit/concepts/delegation/overview/#open-root-delegation)from the buyer smart account. With an open root delegation, the buyer delegates authority without setting a specific delegate. Use [createOpenDelegation](/smart-accounts-kit/reference/delegation/#createopendelegation) to create the open root delegation.

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

warning

Before creating the delegation, make sure your buyer smart account is deployed. If it is not deployed, delegation redemption will fail.

```
import { CaveatType, createOpenDelegation, ScopeType } from '@metamask/smart-accounts-kit'

const facilitators = accepted.extra.facilitators
if (!facilitators || facilitators.length === 0) {
  console.log('No facilitators found in PAYMENT-REQUIRED')
  // Handle the error
}

// Use the amount requested by the seller.
const maxAmount = BigInt(accepted.amount)

const caveats = [
  {
    type: CaveatType.Redeemer,
    redeemers: facilitators,
  },
]

const delegation = createOpenDelegation({
  from: buyerSmartAccount.address,
  environment: buyerSmartAccount.environment,
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: accepted.asset,
    maxAmount,
  },
  caveats,
})

const signature = await buyerSmartAccount.signDelegation({
  delegation,
})

const signedDelegation = {
  ...delegation,
  signature,
}

```

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

Create a payment payload using the signed delegation and accepted requirements. 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.

Use `encodeDelegations` to encode the delegation chain. Then base64 encode the full x402 payment payload before sending it in the `PAYMENT-SIGNATURE` header.

- example.ts
- types.ts

```
import { encodeDelegations } from '@metamask/smart-accounts-kit/utils'
import { PaymentPayload } from './types'

const permissionContext = encodeDelegations([signedDelegation])

const paymentPayload: PaymentPayload = {
  x402Version: 2,
  accepted,
  payload: {
    delegationManager: buyerSmartAccount.environment.DelegationManager,
    permissionContext,
    delegator: buyerSmartAccount.address,
  },
}

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

```

```
export type PaymentPayload = {
  x402Version: 2
  accepted: PaymentRequirements
  payload: {
    delegationManager: `0x${string}`
    permissionContext: `0x${string}`
    delegator: `0x${string}`
  }
}

```

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

Send the encoded x402 payment payload in the `PAYMENT-SIGNATURE` header. If verification succeeds, the server returns the protected data.

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

if (!apiResponse.ok) {
  const errorBody = await apiResponse.json()
  throw new Error(errorBody.error ?? 'API request failed')
}

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

```
