@faremeter/middleware
@faremeter/middleware protects HTTP endpoints with Coinbase’s x402 handshake. It forwards desired payment requirements to a facilitator, inspects X-PAYMENT headers from clients, and retries settlement before letting the request proceed.
Source: GitHub › packages/middlewareThe package ships adapters for Express and Hono plus shared helpers you can reuse in other frameworks.
Quick start (Express)
/premium, the middleware:
- Calls the facilitator’s
/acceptsendpoint to produce canonical requirements. - Returns a
402 Payment Requiredresponse (with the facilitator payload) if the incoming request lacks a validX-PAYMENTheader. - When a header is present, forwards it to
/settle. If settlement succeeds, the request pipeline continues; otherwise another 402 is returned.
API surface
Express adapter
createMiddleware({ facilitatorURL, accepts, cacheConfig? })
Returns an async Express middleware.
facilitatorURL: base URL of your facilitator service (mounted routes from@faremeter/facilitator).accepts: array describing the resources you’re willing to accept. Each entry can be a single relaxed requirement object or an array (to represent fallbacks).resourcedefaults to the incoming request URL if not provided.cacheConfig: optional cache tuning (see below).
Hono adapter
createMiddleware({ facilitatorURL, accepts, cacheConfig? })
Same inputs as the Express variant, returning a MiddlewareHandler. The Hono adapter uses the request URL as the resource string.
Common utilities
handleMiddlewareRequest(args)
Framework-agnostic core used by both adapters. Supply:
resource: unique identifier for the paywalled resource (usually a URL).getHeader(key): function that returns header values from the incoming request.sendJSONResponse(status, body): function that sends a response back to the client.getPaymentRequiredResponse: async function returning the facilitator’s JSON (often wrapped with the cache below).- Plus the shared
facilitatorURLandaccepts.
sendJSONResponse when a 402 should be sent; otherwise it resolves to undefined, signaling the request can proceed.
createPaymentRequiredResponseCache(opts?)
Wrap the facilitator calls with an LRU cache to avoid hammering /accepts on every request.
opts.capacity(default256): maximum number of requirement combinations to store.opts.maxAge(default30_000ms): how long to keep entries.opts.now: override timestamp source for testing.opts.disable: whentrue, returns a pass-through implementation that logs a warning.
accepts are flattened before lookup.
findMatchingPaymentRequirements(accepts, payload)
Given the facilitator’s accept list and an x402 payment payload, returns the most specific matching requirement (prefers matches on asset, network, and scheme). Emits warnings if multiple candidates match.
getPaymentRequiredResponse({ facilitatorURL, accepts, resource })
Performs the raw network call to /accepts, validating the JSON using @faremeter/types/x402.
AgedLRUCache
Lightweight LRU implementation underpinning the cache helper. Useful if you need to memoize related calls.
Usage patterns
- Multiple products: Provide an array of arrays in
acceptsto describe alternative requirement sets. Example:accepts: [[solanaUsdcRequirement, evmUsdcRequirement]]. - Resource-specific metadata: Leave
resourceundefined in the accepts entries to let the middleware fill it with the current request URL. You can override per-route if needed. - Observability: The module uses
["faremeter","middleware"]logger namespace from@logtape/logtape. Hook into it to track settlement success or diagnose mismatched payloads.
Error handling
- Invalid facilitator responses throw an exception (HTTP 500). Instrument upstream logging so you can detect schema regressions quickly.
- When settlement fails (e.g., wrong amount or expired signature), the middleware replays the facilitator payload to the client, prompting another payment.
Related references
@faremeter/facilitator: the server counterpart that aggregates handlers.@faremeter/fetch: client-side tool that interprets the 402 responses produced by this middleware.@faremeter/payment-*: handler factories you can pass to the facilitator and ultimately surface through this middleware.