@faremeter/middleware adds payment walls to your HTTP server. It supports both x402 and MPP protocols. When a request hits a protected route, the middleware checks for a valid payment header. If missing, it returns a payment challenge. If present, it verifies the payment through a handler and allows the request to proceed.
How it works
- A request arrives at a protected endpoint.
- The middleware checks for a payment header (
X-PAYMENTorPAYMENT-SIGNATURE). - If missing: returns
402 Payment Requiredwith the configured requirements. - If present: sends the payment to the facilitator for verification and settlement.
- If the facilitator confirms: the request continues to your handler.
- If the facilitator rejects: returns an error response.
Framework support
| Framework | Import path |
|---|---|
| Express | @faremeter/middleware/express |
| Hono | @faremeter/middleware/hono |
| Custom | @faremeter/middleware/common |
common module provides the core payment verification logic without framework bindings. Use it to integrate with any HTTP server.
Configuration
The middleware supports two configuration modes: in-process handlers and remote facilitator. Both are configured throughCommonMiddlewareArgs. The two modes are mutually exclusive for x402 — pass either x402Handlers/pricing or facilitatorURL/accepts, not both. You can combine remote x402 handlers with in-process MPP handlers using createRemoteX402Handlers.
In-process handlers
Pass payment handlers directly to the middleware. The middleware calls them locally to resolve requirements, verify, and settle payments — no separate facilitator service needed. See the Facilitator guide for how to create handlers.| Option | Type | Description |
|---|---|---|
x402Handlers | FacilitatorHandler[] | Optional. x402 payment handlers for in-process settlement. |
mppMethodHandlers | MPPMethodHandler[] | Optional. MPP method handlers for in-process settlement. |
pricing | ResourcePricing[] | What to charge. Required when using in-process handlers. |
supportedVersions | SupportedVersionsConfig | Optional. Which x402 protocol versions to serve (v1, v2, or both). Defaults to v1 only. |
ResourcePricing is the resource server’s statement of “I want X amount of Y asset paid to Z recipient on W network.” It says nothing about x402 schemes or protocol extras — those are determined by the handlers. The recipient field maps to payTo in the underlying x402PaymentRequirements that the handler produces.
Remote facilitator
Communicate with a separate facilitator service over HTTP for x402 payments. This is the original configuration model and is still fully supported.| Option | Type | Description |
|---|---|---|
facilitatorURL | string | URL of the facilitator server. |
accepts | x402PaymentRequirements[] | Payment methods this endpoint accepts. |
cacheConfig | object | Optional cache configuration for facilitator responses. |
supportedVersions | SupportedVersionsConfig | Optional. Which x402 protocol versions to serve (v1, v2, or both). Defaults to v1 only. See How x402 Works. |
Mixing remote x402 with in-process MPP
UsecreateRemoteX402Handlers to wrap a remote facilitator as in-process handlers, then combine with MPP handlers under a shared pricing config:
Defining payment requirements
Use@faremeter/info to construct payment requirements:
x402Exact returns an array (one entry per legacy network ID), while the EVM x402Exact returns a single object. The middleware’s accepts field supports nested arrays, so both can be passed directly:
Caching
The middleware caches facilitator/accepts responses using an LRU cache with TTL. This reduces the number of requests to the facilitator. Cache configuration is optional.
Dynamic pricing
With in-process handlers, dynamic pricing happens naturally. When the middleware calls a handler’sgetRequirements method, it passes the resource URL and payment requirements as context. The handler can inspect the resource and return different prices per request. You configure base pricing via ResourcePricing and let the handler adjust.
For the remote facilitator path, or when you need full control over per-request pricing from the middleware layer, use handleMiddlewareRequest.
handleMiddlewareRequest — the lower-level API
createMiddleware (used by the Express and Hono integrations) accepts static configuration at initialization. When you need to compute requirements per-request — for example, varying the price based on a query parameter, header, or request body — use handleMiddlewareRequest from @faremeter/middleware/common.
The tradeoff is that you wire up the framework integration yourself: reading headers, sending JSON responses, and calling your route handler.
When to use which
createMiddleware | handleMiddlewareRequest | |
|---|---|---|
| Pricing | Fixed per route | Dynamic per request |
| Framework | Express or Hono | Any HTTP server |
| Setup | One-liner middleware | Manual header/response wiring |
| Use case | Most endpoints | Dynamic pricing, custom frameworks |
Signature
handleMiddlewareRequest accepts a single options object:
| Option | Type | Description |
|---|---|---|
x402Handlers | FacilitatorHandler[] (optional) | x402 payment handlers. |
mppMethodHandlers | MPPMethodHandler[] (optional) | MPP method handlers. |
pricing | ResourcePricing[] | Required. Payment pricing for this request. |
resource | string | The URL being accessed (typically req.url). |
supportedVersions | Required<SupportedVersionsConfig> | Which x402 protocol versions to support. Use resolveSupportedVersions(). |
getHeader | (key: string) => string | undefined | Read a request header. |
sendJSONResponse | (status, body, headers?) => Response | Send a JSON response with status code and optional headers. |
setResponseHeader | (key, value) => void (optional) | Set a response header. |
getBody | () => Promise<ArrayBuffer | null> (optional) | Read the request body (for MPP digest binding). |
body | (ctx: MiddlewareBodyContext) => Promise<Response | void> | Called when a valid payment is received. |
The body callback
The body function runs when the client sends a valid payment. It receives a context object with a protocolVersion discriminant:
x402 v1 context (protocolVersion: 1):
settle(),verify(),paymentPayload,paymentRequirements
protocolVersion: 2):
settle(),verify(),paymentPayload,paymentRequirements
protocolVersion: "mpp"):
settle(),credential
protocolVersion to narrow the context type before accessing protocol-specific fields:
Example: Hono with dynamic pricing
Framework-specific guides
- Express — Express middleware setup.
- Hono — Hono middleware setup.
- Facilitator — Running your own facilitator.