A drop-in x402 facilitator for Base.
One URL swap. WAVE recovers and binds the payer from an EIP-3009 signature, then settles USDC on Base — your server never holds a private key or talks to an RPC node.
One-line swap
Point paymentMiddleware() at WAVE's facilitator URL. It recovers the payer from the signed authorization and broadcasts the on-chain pull from the WAVE relayer. No private key and no RPC node on your server.
EIP-3009 exact scheme
The payer signs a TransferWithAuthorization — amount, recipient, validity window, nonce — as EIP-712 typed data. The credential is cryptographically bound to the payer's wallet; no bearer secret ever leaves the client.
No gas to verify
Verification is pure EIP-712 signature recovery: no gas, no RPC round-trip, no chain dependency. It returns isValid + the recovered payer. Settlement broadcasts the signed pull on Base.
Single-use enforced on-chain
USDC itself rejects a re-used (payer, nonce) authorization per EIP-3009 — the same signature can never settle twice, and that guarantee does not depend on WAVE. A Durable-Object store adds an advisory gas-dedupe layer on top.
Base USDC, mainnet + testnet
USDC on Base mainnet for production; USDC on Base Sepolia for development. Contract addresses are listed below — verify them against your own records before you integrate.
WAVE extension fields
Responses add an optional wave.rail field (e.g. base-usdc) for observability. Further wave.* fields are reserved for compliance and MPP-receipt metadata as those ship. Coinbase-compatible consumers ignore them.
CF SDK — point your x402 server at WAVE (x402-hono / agents/x402)
import { paymentMiddleware } from "x402-hono"; // or agents/x402
app.use(paymentMiddleware(payTo, routes, {
facilitator: { url: "https://gateway.wave.online/v1/x402/facilitator" }, // ← the only change
}));WAVE SDK — payer signing for non-CF agents (@wave-av/agent-money)
import { signExactAuthorization, encodeExactPaymentHeader } from "@wave-av/agent-money";
const payload = await signExactAuthorization({
privateKey: PAYER_KEY, // the agent wallet key — never leaves the client
network: "base", // or "base-sepolia"
to: requirement.payTo, // the merchant treasury address
value: requirement.maxAmountRequired, // atomic USDC; must be >= the requirement
validBefore: Math.floor(Date.now() / 1000) + 600, // a 10-minute window (validAfter + nonce default)
});
const header = encodeExactPaymentHeader("base", payload); // base64
const res = await fetch(resourceUrl, { headers: { "X-Payment": header } });Endpoints
| Path | Behavior |
|---|---|
| POST /v1/x402/facilitator/verify | Pure EIP-712 signature recovery — no gas, no RPC. Returns isValid + the recovered payer. |
| POST /v1/x402/facilitator/settle | Broadcasts the signed EIP-3009 pull from the WAVE relayer on Base. Live, mainnet-proven. |
| GET /.well-known/x402 | Discovery manifest — facilitator URL, scheme, networks, assets. |
| GET /v1/x402/facilitator/supported | CAIP-2 supported networks + schemes, for facilitator-registry discovery. |
| POST /v1/mpp/facilitator/verify | MPP protocol alias — same handler. |
| POST /v1/mpp/facilitator/settle | MPP protocol alias — same handler. |
Supported networks & assets
| Network | Chain | Asset | Contract address |
|---|---|---|---|
| Base mainnet | eip155:8453 | USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Base Sepolia | eip155:84532 | USDC | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
The gateway publishes a /.well-known/x402 discovery manifest and a CAIP-2 /supported endpoint today, so facilitator registries and clients can find it automatically; a _x402 DNS record is on the roadmap. You can also integrate directly by setting the facilitator URL above.
Start with one URL.
Swap the facilitator URL in your x402-hono or agents/x402 config, or sign payer authorizations with the WAVE SDK. The developer portal has the full integration path.