Skip to content
Merged
2 changes: 2 additions & 0 deletions gator-sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ const sidebar = {
type: 'category',
label: 'x402',
collapsed: true,
key: 'x402-guides',
items: [
'guides/x402/seller',
{
type: 'category',
label: 'Buyer',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const sessionAccount = privateKeyToAccount('0x...')

### 3. Get payment requirements

Call the protected API route once without a payment header.
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.
Expand Down Expand Up @@ -222,7 +222,7 @@ For ERC-7710 (Smart Contract Delegation), x402 requires the payload fields `dele
`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.
Encode the full x402 payment payload as base64, then send it in the `PAYMENT-SIGNATURE` header.

<Tabs>
<TabItem value="example.ts">
Expand Down Expand Up @@ -267,13 +267,13 @@ export type PaymentPayload = {

### 7. Make the paid request

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

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

Expand Down
8 changes: 4 additions & 4 deletions smart-accounts-kit/guides/x402/buyer/delegations.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const buyerAccount = privateKeyToAccount('0x<BUYER_PRIVATE_KEY>')

### 2. Get payment requirements

Call the protected API route once without a payment header.
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.
Expand Down Expand Up @@ -194,7 +194,7 @@ For ERC-7710 (Smart Contract Delegation), x402 requires the payload fields `dele
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.
Then base64 encode the full x402 payment payload before sending it in the `PAYMENT-SIGNATURE` header.

<Tabs>
<TabItem value="example.ts">
Expand Down Expand Up @@ -238,13 +238,13 @@ export type PaymentPayload = {

### 5. Make the paid request

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

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

Expand Down
8 changes: 4 additions & 4 deletions smart-accounts-kit/guides/x402/buyer/recurring-payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([

### 4. Get payment requirements

Call the x402-protected endpoint without a payment header to request payment terms
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
Expand Down Expand Up @@ -225,7 +225,7 @@ For ERC-7710 (Smart Contract Delegation), x402 requires the payload fields `dele
`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.
Encode the full x402 payment payload as base64, then send it in the `PAYMENT-SIGNATURE` header.

```ts
import { PaymentPayload } from './types'
Expand All @@ -247,12 +247,12 @@ const encodedPayment = Buffer.from(JSON.stringify(paymentPayload)).toString('bas

### 7. Make the paid request

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

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

Expand Down
164 changes: 164 additions & 0 deletions smart-accounts-kit/guides/x402/seller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
description: Build an x402-compatible Node.js server that accepts ERC-7710 delegation payments.
sidebar_label: Seller
keywords:
[x402, ERC-7710, HTTP 402, Advanced Permissions, facilitator, delegation, Express, Node.js]
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# Create an x402 server with ERC-7710

In this guide, you build a Node.js server that charges for HTTP API access using
[x402](https://www.x402.org/) and accepts [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) delegation
payments verified through the MetaMask facilitator.

You use the official [`@x402/express`](https://www.npmjs.com/package/@x402/express) middleware with a custom ERC-7710 scheme that routes
verification and settlement through the MetaMask facilitator.

## Prerequisites

- [Node.js 18](https://nodejs.org/en) or later.
- A [Node.js Express server](https://expressjs.com/en/starter/installing.html).
- A seller payout address to receive funds (for example, a
[MetaMask wallet](https://metamask.io/download) address).

## Steps

### 1. Install the dependencies

```bash npm2yarn
npm install @x402/core @x402/evm @x402/express cors express
```

### 2. Create the ERC-7710 scheme

Create a custom scheme that extends `ExactEvmScheme` from `@x402/evm` to add ERC-7710
delegation support.

The scheme overrides `enhancePaymentRequirements` to set `assetTransferMethod` to `erc7710`
and include the facilitator addresses so buyers can scope their delegation to a specific
set of facilitators before creating the payment payload.

```ts
import { ExactEvmScheme } from '@x402/evm/exact/server'
import type { PaymentRequirements, SupportedKind } from '@x402/core/types'
import type { FacilitatorClient } from '@x402/core/server'

export class Erc7710ExactEvmScheme extends ExactEvmScheme {
constructor(private readonly facilitatorClient: FacilitatorClient) {
super()
}

async enhancePaymentRequirements(
paymentRequirements: PaymentRequirements,
supportedKind: SupportedKind,
facilitatorExtensions: string[]
): Promise<PaymentRequirements> {
const enhanced = await super.enhancePaymentRequirements(
paymentRequirements,
supportedKind,
facilitatorExtensions
)

const supported = await this.facilitatorClient.getSupported()
const facilitators = [
...(supported.signers[paymentRequirements.network] ?? []),
...(supported.signers['eip155:*'] ?? []),
]

return {
...enhanced,
extra: {
...enhanced.extra,
assetTransferMethod: 'erc7710',
facilitators,
},
}
}
}
```

### 3. Configure the server

Set up the Express server with the x402 `paymentMiddleware` and the custom ERC-7710 scheme.
The `paymentMiddleware` intercepts requests to protected routes and handles the full x402 payment
flow, including requirements advertisement, verification, and settlement.

In this example, you create a protected `GET /api/hello` endpoint that charges 0.01 USDC on
Base mainnet.
Replace the payout address in `src/config.ts` with your own seller wallet address.

<Tabs>
<TabItem value="src/index.ts">

```ts
import express, { type Request, type Response } from 'express'
import cors from 'cors'
import { paymentMiddleware } from '@x402/express'
import { x402ResourceServer } from '@x402/core/server'
import { Erc7710ExactEvmScheme } from './scheme.js'
import { NETWORK_ID, PORT, payToAddress, facilitatorClient } from './config.js'

const app = express()
app.use(cors({ exposedHeaders: ['PAYMENT-REQUIRED', 'PAYMENT-RESPONSE'] }))

app.use(
paymentMiddleware(
{
'GET /api/hello': {
accepts: [
{
scheme: 'exact',
price: '$0.01',
network: NETWORK_ID,
payTo: payToAddress,
},
],
description: 'Access to protected resource',
mimeType: 'application/json',
},
},
new x402ResourceServer(facilitatorClient).register(
NETWORK_ID,
new Erc7710ExactEvmScheme(facilitatorClient)
)
)
)

app.get('/api/hello', (_req: Request, res: Response) => {
res.json({ message: 'Hello!' })
})

app.listen(PORT, () => {
console.log(`[seller] Server running on http://localhost:${PORT}`)
})
```

</TabItem>

<TabItem value="src/config.ts">

```ts
import { HTTPFacilitatorClient } from '@x402/core/server'

export const NETWORK_ID = 'eip155:8453'
export const PORT = 4402

// Replace with your seller payout address.
export const payToAddress = '0x<PAY_TO_ADDRESS>'

// MetaMask facilitator base URL for x402 on Base mainnet.
export const facilitatorClient = new HTTPFacilitatorClient({
url: 'https://tx-sentinel-base-mainnet.dev-api.cx.metamask.io/platform/v2/x402',
})
```

</TabItem>
</Tabs>

## Next steps

- Learn more about [ERC-7710 delegation](../../concepts/delegation/overview.md).
- See the [x402 ERC-7710 specification](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md#3-assettransfermethod-erc-7710).
Loading