Mountable Hono sub-app implementing the x402 facilitator protocol.
In the x402 protocol, a facilitator is the service that verifies payment signatures and settles transactions on-chain. Resource servers delegate payment verification and settlement to a facilitator instead of interacting with blockchains directly.
This package wraps the official Coinbase x402 packages (@x402/core, @x402/evm, @x402/svm) into a Hono sub-app with three endpoints. Mount it on any Hono app and you have a working facilitator — on Cloudflare Workers, Node.js, Bun, Deno, or any other Hono-supported runtime.
pnpm add @oviato/x402-facilitator-honoimport { Hono } from "hono";
import { x402Facilitator } from "@oviato/x402-facilitator-hono";
const app = new Hono();
app.route("/facilitator", await x402Facilitator({
evm: {
privateKey: env.EVM_PRIVATE_KEY,
rpcUrls: {
"eip155:84532": env.RPC_URL_BASE_SEPOLIA,
},
},
}));
export default app;Three endpoints are now live: GET /facilitator/supported, POST /facilitator/verify, POST /facilitator/settle.
interface FacilitatorConfig {
evm?: {
privateKey: string; // Hex, 0x-prefixed. Gas wallet.
rpcUrls: Record<string, string>; // CAIP-2 network ID -> RPC URL
};
svm?: {
privateKey: string; // Base58. Fee payer wallet.
rpcUrls: Record<string, string>; // CAIP-2 network ID -> RPC URL
};
nonceStore?: NonceStore; // Optional. Defaults to in-memory.
}At least one of evm or svm must be provided. Only configured chains appear in /supported.
Use CAIP-2 identifiers:
| Chain | CAIP-2 ID |
|---|---|
| Base Sepolia | eip155:84532 |
| Base | eip155:8453 |
| Ethereum | eip155:1 |
| Solana Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 |
| Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp |
app.route("/facilitator", await x402Facilitator({
evm: {
privateKey: env.EVM_PRIVATE_KEY,
rpcUrls: {
"eip155:84532": env.RPC_URL_BASE_SEPOLIA,
"eip155:8453": env.RPC_URL_BASE,
},
},
svm: {
privateKey: env.SVM_PRIVATE_KEY,
rpcUrls: {
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": env.RPC_URL_SOLANA_DEVNET,
},
},
}));The facilitator uses a nonce store for replay protection. Two implementations are included:
import { x402Facilitator, kvNonceStore } from "@oviato/x402-facilitator-hono";
app.route("/facilitator", await x402Facilitator({
evm: { ... },
nonceStore: kvNonceStore(env.NONCE_KV),
}));import { x402Facilitator, memoryNonceStore } from "@oviato/x402-facilitator-hono";
app.route("/facilitator", await x402Facilitator({
evm: { ... },
nonceStore: memoryNonceStore(), // this is the default
}));Implement the NonceStore interface for Redis, D1, DynamoDB, etc.:
interface NonceStore {
has(nonce: string): Promise<boolean>;
set(nonce: string, ttlSeconds?: number): Promise<void>;
}This package has zero opinions on auth, rate limiting, logging, or CORS. Add whatever middleware you need before the mount:
const app = new Hono();
app.use("/facilitator/*", rateLimiter({ max: 100 }));
app.use("/facilitator/*", apiKeyAuth({ header: "X-API-Key" }));
app.route("/facilitator", await x402Facilitator({ ... }));Resource servers using @x402/hono or @x402/express point their facilitatorUrl at this facilitator:
// On the resource server
import { paymentMiddleware } from "@x402/hono";
app.use("/api/*", paymentMiddleware({
facilitatorUrl: "https://your-facilitator.example.com/facilitator",
// ...
}));Returns which networks and schemes this facilitator supports.
Response:
{
"kinds": [
{ "x402Version": 2, "scheme": "exact", "network": "eip155:84532" }
],
"extensions": [],
"signers": {
"eip155:*": ["0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf"]
}
}Verifies a payment payload against payment requirements. Checks nonce replay protection.
Request body: Standard x402 verify request ({ paymentPayload, paymentRequirements })
Response: Standard x402 verify response ({ isValid, invalidReason?, payer? })
Settles a payment on-chain. Stores the nonce after successful settlement.
Request body: Standard x402 settle request ({ paymentPayload, paymentRequirements })
Response: Standard x402 settle response ({ success, transaction, network, payer? })
- Cloudflare Worker — Minimal wrangler project with KV nonce store
- Node.js — Minimal Node.js server with
@hono/node-server
The facilitator's private key is used as a gas wallet to broadcast settlement transactions. On Base, gas costs are approximately $0.001 per transaction. Fund the gas wallet with a small amount of ETH (or SOL for Solana).
The gas wallet only pays gas fees. It does not hold or custody user funds. Payment tokens (e.g., USDC) are transferred directly from payer to payee via signed authorizations (EIP-3009 / Permit2 on EVM, pre-signed transactions on Solana).
- Never commit private keys to source control
- Use environment variables or secret managers (Cloudflare Secrets, AWS Secrets Manager, etc.)
- The private key is used solely to submit settlement transactions — it cannot access or redirect user funds
- Submit pre-authorized token transfers on behalf of payers
- Pay gas fees for settlement transactions
- Transfer tokens without a valid signed authorization from the payer
- Change the recipient of a payment
- Modify the payment amount
Every payment nonce is checked against the NonceStore before verification. After successful settlement, the nonce is stored to prevent the same payment from being settled twice.
This package is maintained by Oviato — passkey-native, chain-agnostic wallet infrastructure. Oviato lets developers spin up self-custody embedded wallets in seconds using Face ID, Touch ID, or passkeys instead of seed phrases. One SDK, one identity (Ovi.id), across Bitcoin, EVM, Solana, and more.
Backed by Draper VC, Boost VC, CoinGecko, and Etherscan. Try the live demo.
See CONTRIBUTING.md.
- x402 Protocol — The x402 protocol specification and official packages
- @x402/core — Core x402 types and facilitator class
- @x402/evm — EVM payment scheme implementations
- @x402/svm — Solana payment scheme implementations
- @x402/hono — Hono middleware for resource servers
- x402 Facilitator Docs
- Hono — Ultrafast web framework for the Edges