Skip to main content

Overview

x402x-server is the server-side SDK that integrates token detection, payment verification, and settlement to complete the full x402x flow end-to-end: “create payment requirements → parse/verify/settle → return resource.”

Key features

  • Simple API: two-argument starting point, handles complexity automatically
  • Automatic token detection: powered by x402x-detector, with built-in cache
  • Complete payment pipeline: parse → verify → settle all-in-one
  • Dynamic requirements creation: supports both fixed and dynamic pricing
  • Performance: warm-up cache, fast mode, non-blocking initialization
  • Framework middleware: Express / Hono out of the box
  • Type-safety: 100% TypeScript + Zod runtime validation

Install and deps

npm i x402x-server x402x-facilitator viem
Optional (on demand):
# Express
npm i express

# Hono
npm i hono

Quick start

Minimal usage (manual handling)

import { X402Server } from "x402x-server";
import { Facilitator } from "x402x-facilitator";
import { createPublicClient, http } from "viem";
import { bscTestnet } from "viem/chains";

const client = createPublicClient({ chain: bscTestnet, transport: http() });
const f = new Facilitator({ recipientAddress: "0xSeller", waitUntil: "confirmed" });
const server = new X402Server({ client, facilitator: f });

// 1) Create payment requirements (auto or manually specify paymentType)
const reqs = await server.createRequirements({
  asset: "0xToken",
  maxAmountRequired: "1000000",
  description: "Premium API",
});

// 2) Process the payment (parse → verify → settle)
const result = await server.process(req.headers["x-payment"] as string, reqs);

// 3) Return by result
if (!result.success) {
  return res.status(result.status).json(result.response);
}
return res.json({ data: "ok", payer: result.data.payer, txHash: result.data.txHash });
import express from "express";
import { createExpressMiddleware, X402Server } from "x402x-server";
import { Facilitator } from "x402x-facilitator";
import { createPublicClient, http } from "viem";
import { bscTestnet } from "viem/chains";

const app = express();
const client = createPublicClient({ chain: bscTestnet, transport: http() });
const facilitator = new Facilitator({ recipientAddress: "0xSeller", waitUntil: "confirmed" });
const server = new X402Server({ client, facilitator });

const payment = createExpressMiddleware({
  server,
  getToken: () => "0xUSDC",
  getAmount: () => "1000000", // 1 USDC (6 decimals)
  // Optional: getConfig / onError / on402 / onPaymentSuccess
});

app.post("/premium", payment, (req, res) => {
  const { payer, txHash } = req.x402!;
  res.json({ success: true, payer, txHash, data: "Premium content" });
});

app.listen(3000);

Hono middleware

import { Hono } from "hono";
import { createHonoMiddleware } from "x402x-server";

const app = new Hono();
const middleware = createHonoMiddleware({
  server,
  getToken: (c) => c.req.query("token") || "0xUSDC",
  getAmount: async (c) => {
    const body = await c.req.json<{ complexity: number }>();
    return (body.complexity * 100000).toString();
  },
});
app.post("/api", middleware, (c) => {
  const x402 = c.get("x402") as { payer: string; txHash: string };
  return c.json({ data: "resource", payer: x402.payer, txHash: x402.txHash });
});

Core capabilities

1) Automatic token detection

const requirements = await server.createRequirements({
  asset: "0xUSDC",
  maxAmountRequired: "1000000",
  // Default autoDetect: true — detector selects paymentType automatically
});
// Possible choice: eip3009 / permit / permit2 (priority: eip3009 > permit > permit2)

2) All-in-one: parse → verify → settle

const result = await server.process(paymentHeader, requirements);
// Success: { success: true, status: 200, data: { payer, txHash } }
// Failure (client): { success: false, status: 402, errorStage: "parse" | "verify", response }
// Failure (server settlement): { success: false, status: 500, errorStage: "settle", response, error }

3) Config and utilities

const server = new X402Server({ client, facilitator, network: "bsc-testnet" });
await server.initialize(["0xUSDC"]);          // warm-up (non-blocking)
server.getCacheStats();                        // { size, keys }
await server.clearCache();                     // clear cache
server.get402Response(requirements, "reason"); // build standard 402 response

Utilities

  • initialize(tokens): warm up detector cache (cache hits in <1ms)
  • get402Response(reqs, message?): build standard 402 response body
  • getCacheStats/clearCache: inspect/clear cache

API reference (condensed)

class X402Server {
  constructor(config: { client: PublicClient; facilitator: Facilitator; network?: string });
  initialize(tokens: string[]): Promise<{ success: boolean; detected?: number; total?: number; error?: string }>;
  createRequirements(config: {
    asset: string;
    maxAmountRequired: string;
    network?: string;
    scheme?: "exact";
    outputSchema?: Record<string, unknown>;
    paymentType?: "permit" | "eip3009" | "permit2" | "auto";
    resource?: string;
    description?: string;
    mimeType?: string;
    maxTimeoutSeconds?: number;
    extra?: Record<string, unknown>;
    autoDetect?: boolean;
  }): Promise<PaymentRequirements>;
  process(paymentHeader: string | undefined, requirements: PaymentRequirements): Promise<
    | { success: true; status: 200; data: { payer: string; txHash: string } }
    | { success: false; status: 402; errorStage: "parse" | "verify"; response: Response402 }
    | { success: false; status: 500; errorStage: "settle"; response: Response402; error: string }
  >;
  parse(paymentHeader: string | undefined, requirements: PaymentRequirements): ParseResult;
  verify(parsed: ParsedPayment): Promise<VerifyResult>;
  settle(parsed: ParsedPayment): Promise<SettleResult>;
  get402Response(requirements: PaymentRequirements, error?: string): Response402;
  clearCache(tokenAddress?: string): Promise<void>;
  getCacheStats(): { size: number; keys: string[] };
}

Performance and optimization

  • Warm up cache: initialize([tokens]) at service startup
  • Fast mode: createRequirements({ paymentType: "permit", autoDetect: false }) (<1ms)
  • Reuse requirements: reuse the same requirements for fixed-price endpoints
  • Background initialization: don’t block startup; log once ready
Performance reference:
OperationFirst callCached call
createRequirements(autoDetect: true)2–5s<1ms
createRequirements(autoDetect: false)<1ms<1ms
process()2–5s + network<1ms + network

Best practices

  • Use env vars for recipientAddress, RPC, etc.
  • Distinguish error stages: parse/verify → 402; settle → 500
  • Record on-chain tx hash; build reconciliation and retry mechanisms
  • Centralize logs and metrics for observability and tuning

Resources

  • Source: https://github.com/WTFLabs-WTF/x402x/tree/main/typescript/packages/x402x-server
  • Issues: https://github.com/WTFLabs-WTF/x402x/issues