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.
npx x402-fl dev
That's it. Behind the scenes, x402-fl:
- Forks Base mainnet using Anvil with real USDC contract state, at zero cost
- Starts a facilitator server that verifies and settles x402 payments locally
- Provides a
fundcommand to mint USDC to any address instantly
- Node.js 20+
- pnpm
- One of:
- Foundry (recommended, provides
anvil) - Docker (fallback, runs Anvil in a container; also required for Testcontainers)
- Foundry (recommended, provides
Try it instantly with npx:
npx x402-fl devOr install globally:
npm install -g x402-fl
x402-fl devThis starts Anvil on port 8545 and launches the facilitator on port 4022.
git clone https://github.com/kevzzsk/x402-fl.git
cd x402-fl
pnpm install
pnpm devFund an account with 100 USDC:
x402-fl fund 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 100Start 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-keyis not recommended
Note: anvil state is not persisted.
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 |
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 |
The facilitator server exposes the following HTTP endpoints (default http://localhost:4022):
Verify an x402 payment payload without settling it.
Request body:
{
"paymentPayload": { ... },
"paymentRequirements": { ... }
}Response: Verification result from the facilitator.
Settle (execute) a verified x402 payment on-chain.
Request body:
{
"paymentPayload": { ... },
"paymentRequirements": { ... }
}Response: Settlement result with transaction details.
List supported payment schemes and networks.
Response:
{ ... }Health check endpoint.
Response:
{
"status": "ok",
"networks": ["eip155:8453", "eip155:84532"],
"facilitator": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
}A pre-built Docker image is available on GitHub Container Registry:
docker pull ghcr.io/kevzzsk/x402-fl:latestRun it directly:
docker run -p 4022:4022 -p 8545:8545 ghcr.io/kevzzsk/x402-fl:latestOverride 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) |
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.
The testcontainers package is an optional peer dependency:
pnpm install -D testcontainersimport { 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");
});
});| 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 |
| 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.
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.
- 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
Found a bug or have a feature request? Open an issue.
MIT