Hosted facilitator (Base Sepolia)

The facilitator is the rail (verify + settle). The paid weather route is a separate example seller. Public builder: Capt. Riker (@BatchRail).

Two hosts. Do not call facilitator.batchrail.io/weather — that path does not exist.
Rail: facilitator.batchrail.io
Seller: demo-resource … /weather (browser → 402)
Testnet only. Network eip155:84532. No API key. Cache /supported (not every request).

Exact vs batch

exactbatch-settlement
v2 price fieldamountamount (not v1 maxAmountRequired)
USDC reaches payToon that request’s POST /settleafter your claim job, then settle
ChannelManagernot requiredrequired — the rail does not auto-enrol payTo

Read receiverAuthorizer from live /supported. Do not hardcode it. Batch serves after verify, before the voucher is on-chain — claim on a timer and if a buyer starts withdrawal.

Try a paid call (testnet)

Live example seller — no repo clone required:

A normal browser gets HTTP 402 (expected). An x402 client pays with Base Sepolia test USDC (this demo uses batch-settlement), retries, and receives a small JSON payload. The seller uses the rail at facilitator.batchrail.io.

Env vars (yours)

FACILITATOR_URL=https://facilitator.batchrail.io
EVM_ADDRESS=0xYourReceiveAddressOnBaseSepolia

You never need BatchRail private keys. EVM_ADDRESS is your pay-to wallet.

Facilitator endpoints (the rail)

PathMeaning
/healthService up
/statsPublic usage counters
/supportedBase Sepolia schemes only
POST /verifyVerify payment
POST /settleRelay on-chain actions

429: { "error": "rate_limit_exceeded" } + Retry-After: 60. Limit 120/min/IP. /health and /stats are excluded.

1. Minimal Express — one protected route

import express from "express";
import { paymentMiddlewareFromHTTP, x402ResourceServer } from "@x402/express";
import { HTTPFacilitatorClient } from "@x402/core/server";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server";

const NETWORK = "eip155:84532"; // Base Sepolia testnet
const payTo = process.env.EVM_ADDRESS;

const facilitatorClient = new HTTPFacilitatorClient({
  url: process.env.FACILITATOR_URL ?? "https://facilitator.batchrail.io",
});

const batchScheme = new BatchSettlementEvmScheme(payTo);
const resourceServer = new x402ResourceServer(facilitatorClient)
  .register(NETWORK, batchScheme);

const app = express();

app.get(
  "/weather",
  paymentMiddlewareFromHTTP(
    {
      accept: [{
        scheme: "batch-settlement",
        network: NETWORK,
        payTo,
        amount: "10000",
        resource: "https://your-host.example/weather",
        description: "Test weather (Base Sepolia)",
        mimeType: "application/json",
      }],
    },
    resourceServer
  ),
  (_req, res) => res.json({ ok: true, note: "paid on testnet" })
);

app.listen(4021);

Batch still needs your ChannelManager. For exact-only, use scheme: "exact" — no manager. Full examples: github.com/BatchRail/core.

2. MCP / agent-tool sellers

Same facilitator rail. One paid tool endpoint on Base Sepolia:

FACILITATOR_URL=https://facilitator.batchrail.io
EVM_ADDRESS=0xYourAddress
NETWORK=eip155:84532   // testnet only

// On tool call:
// 1) 402 + scheme + network + payTo + amount
// 2) verify/settle via FACILITATOR_URL
// 3) run tool, return result
// batch-settlement still needs your claim job
Testnet warning. No mainnet. Test USDC only. Do not ship production keys in a public demo client. Mainnet fees are not set.

Gas & wallets

USDC (Base Sepolia): 0x036CbD53842c5426634e7929541eC2318f3dCF7e

Questions → @BatchRail (Capt. Riker).