Use this file to discover all available pages before exploring further.
This guide walks you through setting up an Express server that accepts x402r escrow-backed payments. By the end, you’ll have a paid API endpoint protected by the x402 payment middleware with refundable escrow support.
# Replace ADDRESS with your merchant address.ADDRESS=0x321651df4593DA57C413579c5b611D1A90168a3A# Replace OPERATOR_ADDRESS with the operator you deployed.OPERATOR_ADDRESS=0xa0d4734842df1690a5B33Cb21828c946e39D55a2FACILITATOR_URL=http://localhost:4022
3
Create the server
Create index.ts:
import "dotenv/config";import express from "express";import { paymentMiddleware, x402ResourceServer } from "@x402/express";import { AuthCaptureEvmScheme } from "@x402r/evm/auth-capture/server";import { getChainConfig } from "@x402r/core";import { HTTPFacilitatorClient } from "@x402/core/server";const address = process.env.ADDRESS as `0x${string}`;const operatorAddress = process.env.OPERATOR_ADDRESS as `0x${string}`;if (!address || !operatorAddress) { console.error("Missing required environment variables: ADDRESS, OPERATOR_ADDRESS"); process.exit(1);}const facilitatorUrl = process.env.FACILITATOR_URL;if (!facilitatorUrl) { console.error("FACILITATOR_URL environment variable is required"); process.exit(1);}const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl });const networkId = "eip155:84532";const app = express();const now = Math.floor(Date.now() / 1000);app.use( paymentMiddleware( { "GET /weather": { accepts: [ { scheme: "auth-capture", price: "$0.01", network: networkId, payTo: address, maxTimeoutSeconds: 60, extra: { name: "USDC", version: "2", captureAuthorizer: operatorAddress, captureDeadline: now + 60 * 60, // capture within 1 hour refundDeadline: now + 24 * 60 * 60, // refund window 24 hours feeRecipient: operatorAddress, minFeeBps: 0, maxFeeBps: 500, // assetTransferMethod defaults to "eip3009" // autoCapture defaults to false (two-phase) }, }, ], description: "Weather data", mimeType: "application/json", }, }, new x402ResourceServer(facilitatorClient).register( networkId, new AuthCaptureEvmScheme(), ), ),);app.get("/weather", (req, res) => { res.send({ report: { weather: "sunny", temperature: 70 }, });});app.listen(4021, () => { console.log("Server listening at http://localhost:4021");});
4
Start the server
npx tsx index.ts
You should see:
Server listening at http://localhost:4021
5
Test the endpoint
curl http://localhost:4021/weather
Without a valid payment header, the server responds with HTTP 402 and the auth-capture payment requirements:
extra config declares the captureAuthorizer, capture/refund deadlines, fee recipient, and fee bounds. The canonical AuthCaptureEscrow and token collector addresses are universal CREATE2 deploys, so routes do not need to repeat them.
AuthCaptureEvmScheme registers the auth-capture payment scheme with the x402 resource server so it can verify auth-capture-backed payments.
paymentMiddleware intercepts requests, checks for a valid payment header, and returns 402 when the caller has not provided one.
HTTPFacilitatorClient connects to the facilitator service that verifies and settles payments on-chain.