Skip to content

kevzzsk/x402-fl

Repository files navigation

x402-fl: Local x402 Payment Facilitator

npm version License: MIT

A local x402 facilitator for development and testing. One command gives you a fully functional x402 payment environment: a forked Base mainnet via Foundry Anvil paired with a local facilitator server. Build and test x402-powered apps without touching real funds.

Warning: Local development only. Uses Anvil's deterministic private keys, which are publicly known and provide zero security. Do not use in production.

Note: Currently supports USDC on Base and Base Sepolia. Custom ERC-20 token support is on the roadmap.

What it does

npx x402-fl dev

That's it. Behind the scenes, x402-fl:

  1. Forks Base mainnet using Anvil with real USDC contract state, at zero cost
  2. Starts a facilitator server that verifies and settles x402 payments locally
  3. Provides a fund command to mint USDC to any address instantly

Prerequisites

Quick Start

Try it instantly with npx:

npx x402-fl dev

Or install globally:

npm install -g x402-fl
x402-fl dev

This starts Anvil on port 8545 and launches the facilitator on port 4022.

From source

git clone https://github.com/kevzzsk/x402-fl.git
cd x402-fl
pnpm install
pnpm dev

Fund an account with 100 USDC:

x402-fl fund 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 100

CLI Commands

x402-fl dev

Start Anvil fork + facilitator server for local x402 development.

x402-fl dev [options]
Flag Default Description
--port <number> 4022 Facilitator HTTP port
--anvil-port <number> 8545 Anvil RPC port (first instance; additional instances use next ports)
--network <name...> base Network preset(s) to fork — repeatable (e.g. --network base --network base-sepolia)
--rpc-url <url> https://mainnet.base.org RPC URL to fork (overrides the first --network preset's default)
-v Show facilitator request logs
-vv Show facilitator request logs and Anvil process logs
--private-key <key> Custom facilitator private key (prefer default Anvil account)

The --network flag controls which chains get a local Anvil fork. Specify it multiple times to run multiple Anvil instances (e.g. --network base --network base-sepolia). The facilitator always registers all supported schemes across all configured networks, so GET /supported will list every scheme/network combination.

Warning: --private-key is not recommended

Note: anvil state is not persisted.

x402-fl fund

Fund any address with USDC on the local Anvil fork.

x402-fl fund <address> <amount> [options]
Argument / Flag Default Description
<address> required 0x-prefixed Ethereum address to fund
<amount> required USDC amount in major units (human-readable, e.g. 100 or 1.5)
--anvil-port <number> 8545 Anvil RPC port

x402-fl balance

Check USDC balance for an address on the local Anvil fork.

x402-fl balance <address> [options]
Argument / Flag Default Description
<address> required 0x-prefixed Ethereum address
--anvil-port <number> 8545 Anvil RPC port

Facilitator API Endpoints

The facilitator server exposes the following HTTP endpoints (default http://localhost:4022):

POST /verify

Verify an x402 payment payload without settling it.

Request body:

{
  "paymentPayload": { ... },
  "paymentRequirements": { ... }
}

Response: Verification result from the facilitator.

POST /settle

Settle (execute) a verified x402 payment on-chain.

Request body:

{
  "paymentPayload": { ... },
  "paymentRequirements": { ... }
}

Response: Settlement result with transaction details.

GET /supported

List supported payment schemes and networks.

Response:

{ ... }

GET /health

Health check endpoint.

Response:

{
  "status": "ok",
  "networks": ["eip155:8453", "eip155:84532"],
  "facilitator": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
}

Docker

A pre-built Docker image is available on GitHub Container Registry:

docker pull ghcr.io/kevzzsk/x402-fl:latest

Run it directly:

docker run -p 4022:4022 -p 8545:8545 ghcr.io/kevzzsk/x402-fl:latest

Override the fork RPC URL:

docker run -p 4022:4022 -p 8545:8545 ghcr.io/kevzzsk/x402-fl:latest --rpc-url https://your-rpc-url.com
Tag Description
latest Latest stable release
next Pre-release builds (e.g. 1.0.0-beta.1)
x.y.z Pinned version (e.g. ghcr.io/kevzzsk/x402-fl:0.1.0)

Testcontainers

x402-fl ships a Testcontainers module so you can spin up a fully isolated x402 environment in integration tests. The container pulls the GHCR image by default.

Install

The testcontainers package is an optional peer dependency:

pnpm install -D testcontainers

Usage

import { describe, it, expect, beforeAll, afterAll } from "vitest";
import {
  X402FacilitatorLocalContainer,
  type StartedX402FacilitatorLocalContainer,
  accounts,
} from "x402-fl/testcontainers";

describe("x402 integration", () => {
  let container: StartedX402FacilitatorLocalContainer;

  beforeAll(async () => {
    container = await new X402FacilitatorLocalContainer().start();
  });

  afterAll(async () => {
    await container?.stop();
  });

  it("facilitator is healthy", async () => {
    const res = await fetch(`${container.getFacilitatorUrl()}/health`);
    expect(res.status).toBe(200);
  });

  it("funds an address with USDC", async () => {
    await container.fund(accounts.facilitator.address, "100");
  });
});

API

X402FacilitatorLocalContainer

Method Description
new X402FacilitatorLocalContainer(image?) Create a container (default: ghcr.io/kevzzsk/x402-fl:latest)
.withNetworkPreset(...names) Select network preset(s) — pass multiple for multi-Anvil (chainable)
.withForkUrl(url) Set a custom RPC URL to fork (chainable)
.start() Build the image (if needed) and start the container

StartedX402FacilitatorLocalContainer

Method Description
.getRpcUrl(network?) Anvil RPC endpoint (pass network name for multi-network setups)
.getFacilitatorUrl() Facilitator HTTP endpoint (http://host:port)
.fund(address, amount, network?) Mint USDC to an address (network name selects Anvil instance)
.balance(address, network?) Get USDC balance (network name selects Anvil instance)
.getPublicClient(network?) Get a viem PublicClient (network name selects Anvil instance)
.stop() Stop and remove the container

Note: The first call to .start() pulls the Docker image from GHCR, which may take a moment. Subsequent calls reuse the cached image. You can pass a custom image tag to the constructor if needed.

Test Accounts

The facilitator uses Anvil's default deterministic account (index 0). Do not use these keys for anything real.

Role Address
Facilitator 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266

Any address can be funded using x402-fl fund.

Roadmap

  • Custom Asset support (EIP-3009 tokens)
  • Custom Fork url
  • Custom Fork block height
  • Dockerised anvil node (fallback when Foundry is not installed)
  • Testcontainers for facilitator + anvil for deterministic testing env
  • Support all anvil args and passdown the args
  • Support SVM

Issues

Found a bug or have a feature request? Open an issue.

License

MIT

About

Local x402 payment facilitator for development and testing. Fork Base mainnet with Anvil, verify and settle x402 payments locally.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors