@fastxyz/x402-server
v1.0.1
Published
Server SDK for the x402 HTTP Payment Protocol — Express middleware for paywall and payment verification
Keywords
Readme
@fastxyz/x402-server
Server SDK for the x402 HTTP Payment Protocol. Protect API routes with payment requirements using Express middleware.
Use Cases
- Protect API routes with payment requirements (HTTP 402)
- Add payment middleware to an Express app
- Create payment requirements for specific routes
- Verify or settle payments via a facilitator
Out of scope: Paying for 402-protected content → @fastxyz/x402-client · Running a facilitator service → @fastxyz/x402-facilitator
Installation
pnpm add @fastxyz/x402-serverQuick Start
Protect a Single Route with paywall
Use paywall to protect a single route with one price and network config:
import express from 'express';
import { paywall } from '@fastxyz/x402-server';
const app = express();
app.use(
paywall(
{ fast: 'fast1merchant...' },
{
price: '$0.10',
network: 'fast-testnet',
networkConfig: {
asset: '0x...',
decimals: 6,
},
},
{ url: 'https://facilitator.example.com' }, // facilitator endpoint
),
);
app.get('/premium', (req, res) => {
res.json({ content: 'exclusive data' });
});
app.listen(3000);Protect Multiple Routes with paymentMiddleware
Use paymentMiddleware to define different price configs per route:
import express from 'express';
import { paymentMiddleware } from '@fastxyz/x402-server';
const app = express();
app.use(
paymentMiddleware(
{ evm: '0x123...' }, // payTo: EVM address for all payments
{
// RoutesConfig: pattern → RouteConfig
'/basic': {
price: '$0.01',
network: 'arbitrum-sepolia',
// NOTE: In production, use environment variables or a config service for asset addresses
networkConfig: { asset: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', decimals: 6 },
},
'/premium': {
price: '$0.10',
network: 'arbitrum-sepolia',
// NOTE: In production, use environment variables or a config service for asset addresses
networkConfig: { asset: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d', decimals: 6 },
config: { description: 'Premium tier content' },
},
},
{ url: 'https://facilitator.example.com' },
),
);
app.get('/basic', (req, res) => res.json({ tier: 'basic' }));
app.get('/premium', (req, res) => res.json({ tier: 'premium' }));
app.listen(3000);Payment Flow
Client Server Facilitator
│ │ │
├── GET /premium ────────►│ │
│◄── 402 + PaymentReq ───┤ │
│ │ │
├── GET /premium ────────►│ │
│ (X-PAYMENT header) ├── POST /verify ──────────►│
│ │◄── { isValid: true } ─────┤
│ │ │
│◄── 200 + content ──────┤ │
│ ├── POST /settle ──────────►│
│ │◄── { success: true } ─────┤API
paywall(payTo, config, facilitator, options?)
Express middleware that protects all requests matched at the mount point with a single payment requirement.
Parameters:
| Param | Type | Description |
| ------------- | ------------------- | --------------------------------------- |
| payTo | PayToConfig | Recipient address config |
| config | RouteConfig | Payment config for the mounted route(s) |
| facilitator | FacilitatorConfig | Facilitator endpoint ({ url }) |
| options | MiddlewareOptions | Optional middleware config |
paymentMiddleware(payTo, routes, facilitator, options?)
Express middleware for multiple route patterns.
RouteConfig
interface RouteConfig {
price: string; // "$0.10", "0.1 USDC"
network: string; // "fast-testnet", "arbitrum-sepolia"
networkConfig: NetworkConfig;
config?: {
description?: string;
mimeType?: string;
asset?: string; // Override networkConfig.asset
};
}
interface NetworkConfig {
asset: string; // USDC contract/token address
decimals: number; // Token decimals (typically 6)
extra?: Record<string, unknown>;
}FacilitatorConfig
interface FacilitatorConfig {
/** Facilitator URL (e.g., "http://localhost:3002") */
url: string;
/** Optional factory for auth headers on verify/settle calls to the facilitator */
createAuthHeaders?: () => Promise<{
verify?: Record<string, string>;
settle?: Record<string, string>;
}>;
}Low-Level Functions
createPaymentRequirement(payTo, routeConfig, resource)— create aPaymentRequirementcreatePaymentRequired(payTo, routeConfig, resource)— format a 402 response bodyverifyPayment(payload, requirement, facilitator)— verify via facilitatorsettlePayment(payload, requirement, facilitator)— settle via facilitatorverifyAndSettle(payload, requirement, facilitator)— verify then settle
Re-exported Express Types
The middleware module re-exports minimal Express-compatible types for use in type annotations:
import type { Request, Response, NextFunction } from '@fastxyz/x402-server';These are framework-compatible (Express, Koa, etc.) as long as they follow the same method, path, header(), status(), json(), setHeader() signature.
Common Pitfalls
- DO NOT omit
networkConfiginRouteConfig— there are no hardcoded network defaults. - DO NOT forget the
facilitator.url— the server needs a facilitator endpoint to verify/settle payments. - DO NOT use raw token amounts in
price— use human-readable formats like"$0.10"or"0.1 USDC". - DO NOT hardcode asset addresses across environments — pass them via
networkConfigper route.
Design
- No hardcoded network configs — all asset info provided via
RouteConfig.networkConfig - Facilitator-agnostic — pass any facilitator URL; no embedded chain logic
- Framework-compatible — works with Express and compatible frameworks (req/res/next signature)
