Skip to main content

@faremeter/facilitator

@faremeter/facilitator bundles an opinionated Hono router that speaks Coinbase’s x402 protocol. It turns one or more FacilitatorHandlers (see @faremeter/types/facilitator) into three public endpoints your services can expose:
Source: GitHub › packages/facilitator
  • POST /accepts – aggregate handler intents into a canonical set of payment requirements.
  • POST /settle – ask handlers to settle a client payment payload.
  • GET /supported – advertise the payment kinds each handler understands.
It also ships Promise utilities that keep handlers from hanging the facilitator forever.

Quick start

import { createFacilitatorRoutes } from "@faremeter/facilitator";
import { createFacilitatorHandler as createSolanaHandler } from "@faremeter/payment-solana/exact";
import { Hono } from "hono";

// 1. Implement one or more FacilitatorHandler instances.
const solanaHandler = createSolanaHandler(
  "mainnet-beta",
  rpc,               // Rpc<SolanaRpcApi>
  feePayerKeypair,
  usdcMintPublicKey,
);

// 2. Wrap them with the facilitator router.
const routes = createFacilitatorRoutes({
  handlers: [await solanaHandler],
  timeout: {
    getRequirements: 750,
    getSupported: 500,
  },
});

// 3. Mount on your server.
const app = new Hono();
app.route("/facilitator", routes);
Requests that fail validation return structured x402 error payloads so clients can gracefully retry or fall back.

API surface

createFacilitatorRoutes({ handlers, timeout? })

  • handlers: array of FacilitatorHandlers. Each handler implements getSupported, getRequirements, and handleSettle (returning null when the request is not for them).
  • timeout: optional per-phase limits (in milliseconds). When provided, getRequirements and getSupported calls are wrapped with allSettledWithTimeout.
The returned router is a ready-to-mount Hono App. You can mount it as-is or cherry-pick handlers (e.g. routes.fetch("/accepts", ...)) if you need advanced composition.

allSettledWithTimeout(promises, timeoutMs)

Wraps an array of promises with an individual timeout guard and returns Promise.allSettled results. Useful for fan-out operations where some backends may be slow or unavailable.

timeout(timeoutMs, message?) and sleep(delayMs, value?)

Small utilities used internally but exported for convenience when composing facilitator handlers.

Request lifecycle

  1. Client hits protected resource and receives 402. Your API middleware (see @faremeter/middleware) forwards its desired payment requirements to /accepts.
  2. Facilitator collects offers. Each handler returns compatible requirements (with network-specific extras filled in). The facilitator collapses the array and responds to the middleware.
  3. Client pays and retries. After the client submits a payment payload, the middleware forwards it to /settle.
  4. Handler validates and settles. If a handler accepts, it returns x402SettleResponse with success: true. Otherwise the facilitator returns a 402 again, letting the client retry with another offer.
Because handlers execute sequentially, order your array from fastest/most-specific to slowest/fallback handlers.

Usage patterns

  • Multi-network support: Register one handler per network (e.g., Solana + EVM). The facilitator walks the array until one claims the settlement request.
  • Timeout tuning: The defaults (500 ms) work for low-latency handlers. Increase them for on-chain reads (e.g., verifying Solana blockhashes) to avoid unnecessary timeouts.
  • Logging: The router uses @logtape/logtape namespaces ["faremeter","facilitator"]. Configure log sinks there if you need structured tracing.
  • @faremeter/types: type definitions for facilitator handlers and x402 payloads.
  • @faremeter/payment-solana / @faremeter/payment-evm: drop-in handler factories for Solana and EVM assets.
  • @faremeter/middleware: HTTP middleware that pairs with this facilitator to protect application routes.