Skip to main content

Overview

x402x-facilitator is the “payment processor” for the x402x payment protocol. It verifies payment signatures (verify), performs on-chain settlement (settle), and provides capability queries (supported). It connects your service to the blockchain for a secure and observable payment flow.

Key features

  • Verify: validate signature, amount, and identity — fast and off-chain
  • Settle: submit on-chain transaction and return tx hash (gas sponsored by the Facilitator)
  • Supported: query payment types supported by chains/tokens
  • EIP-7702: support code delegation for merchant addresses
  • Flexible waiting strategy: simulated | submitted | confirmed

Install

npm i x402x-facilitator

Quick start

import { Facilitator } from "x402x-facilitator";
const f = new Facilitator({ recipientAddress: "0xSeller", waitUntil: "confirmed" });
await f.verify(payload, requirements);
await f.settle(payload, requirements);         // returns transaction hash
const supported = await f.supported();         // { kinds, networks, ... }

Core concepts

Verify vs Settle

  • Verify: off-chain, <100ms; validates signature/amount/authorization (recommended before settlement)
  • Settle: on-chain; returns transactionHash; gas is paid by a relayer
type VerifyResponse = { success: boolean; payer?: string; error?: string };
type SettleResponse = { success: boolean; transactionHash?: string; error?: string };

Waiting strategy (WaitUntil)

type WaitUntil = "simulated" | "submitted" | "confirmed";
// - simulated: only simulate (fastest)
// - submitted: wait until submitted to mempool (fast)
// - confirmed: wait for on-chain confirmation (safest; default in prod)

Recipient / Relayer

  • recipientAddress: merchant address (supports EIP-7702)
  • relayer: relayer address (optional, default built-in)

Configuration highlights

  • recipientAddress: merchant address (EIP-7702)
  • waitUntil: “simulated” | “submitted” | “confirmed”

Scenario tips

  • Perform verify before settle for a more robust flow
  • Log settlement failures for reconciliation and compensation

API reference (condensed)

class Facilitator {
  constructor(config: {
    recipientAddress: string;
    relayer?: string;
    waitUntil?: "simulated" | "submitted" | "confirmed";
    baseUrl?: string;
    apiKey?: string;
  });
  verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<{
    success: boolean; payer?: string; error?: string;
  }>;
  settle(
    payload: PaymentPayload,
    requirements: PaymentRequirements,
    waitUntil?: "simulated" | "submitted" | "confirmed"
  ): Promise<{ success: boolean; transactionHash?: string; error?: string }>;
  supported(filters?: { chainId?: number; tokenAddress?: string }): Promise<{ kinds: string[] }>;
  getConfig(): Required<FacilitatorConfig>;
}

Usage examples

Basic payment flow

const verifyResult = await f.verify(payload, requirements);
if (!verifyResult.success) throw new Error(verifyResult.error);

const settleResult = await f.settle(payload, requirements); // third param can override waitUntil
if (!settleResult.success) throw new Error(settleResult.error);

console.log("payer:", verifyResult.payer, "tx:", settleResult.transactionHash);

Verify-only mode

const result = await f.verify(payload, requirements);
if (result.success) {
  // Validate user intent only; no on-chain transaction
  await grantAccess(result.payer!);
}

Dynamic waiting strategy

const getWait = (amount: string) => BigInt(amount) > BigInt("10000000") ? "confirmed" : "submitted";
const waitUntil = getWait(requirements.maxAmountRequired);
const settled = await f.settle(payload, requirements, waitUntil);

Best practices

  • Use confirmed by default in production; consider submitted for small amounts
  • Classify and log errors; support reconciliation and retries
  • Use environment variables to manage recipientAddress, API keys, etc.

Resources

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