@oviato/x402-facilitator-hono
v1.0.0
Published
Mountable Hono sub-app implementing the x402 facilitator protocol
Maintainers
Readme
@oviato/x402-facilitator-hono
Mountable Hono sub-app implementing the x402 facilitator protocol.
What is this?
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.
Install
pnpm add @oviato/x402-facilitator-honoQuick Start
import { 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.
Configuration
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.
Network identifiers
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 |
With EVM + Solana
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,
},
},
}));Nonce Stores
The facilitator uses a nonce store for replay protection. Two implementations are included:
Cloudflare KV (distributed deployments)
import { x402Facilitator, kvNonceStore } from "@oviato/x402-facilitator-hono";
app.route("/facilitator", await x402Facilitator({
evm: { ... },
nonceStore: kvNonceStore(env.NONCE_KV),
}));In-memory (single-instance deployments)
import { x402Facilitator, memoryNonceStore } from "@oviato/x402-facilitator-hono";
app.route("/facilitator", await x402Facilitator({
evm: { ... },
nonceStore: memoryNonceStore(), // this is the default
}));Custom implementation
Implement the NonceStore interface for Redis, D1, DynamoDB, etc.:
interface NonceStore {
has(nonce: string): Promise<boolean>;
set(nonce: string, ttlSeconds?: number): Promise<void>;
}Adding Middleware
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({ ... }));Connecting Resource Servers
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",
// ...
}));API Reference
GET /supported
Returns which networks and schemes this facilitator supports.
Response:
{
"kinds": [
{ "x402Version": 2, "scheme": "exact", "network": "eip155:84532" }
],
"extensions": [],
"signers": {
"eip155:*": ["0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf"]
}
}POST /verify
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? })
POST /settle
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? })
Examples
- Cloudflare Worker — Minimal wrangler project with KV nonce store
- Node.js — Minimal Node.js server with
@hono/node-server
Gas Costs
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).
Security
Private key handling
- 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
What the gas wallet can do
- Submit pre-authorized token transfers on behalf of payers
- Pay gas fees for settlement transactions
What the gas wallet cannot do
- Transfer tokens without a valid signed authorization from the payer
- Change the recipient of a payment
- Modify the payment amount
Nonce replay protection
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.
Branch Protection
After creating the GitHub repository, configure these branch protection rules for main:
- Require pull request before merging (no direct pushes)
- Require 1 approval
- Dismiss stale PR approvals when new commits are pushed
- Require review from code owners (see
.github/CODEOWNERS) - Require status checks to pass before merging
- Require branches to be up to date before merging
Contributing
See CONTRIBUTING.md.
Related
- 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
