> ## Documentation Index
> Fetch the complete documentation index at: https://docs.faremeter.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware Overview

> Server-side middleware for accepting x402 and MPP payments on your API.

`@faremeter/middleware` adds payment walls to your HTTP server. It supports both x402 and [MPP](/concepts/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.

```bash theme={null}
pnpm add @faremeter/middleware
```

## How it works

1. A request arrives at a protected endpoint.
2. The middleware checks for a payment header (`X-PAYMENT` or `PAYMENT-SIGNATURE`).
3. If missing: returns `402 Payment Required` with the configured requirements.
4. If present: sends the payment to the facilitator for verification and settlement.
5. If the facilitator confirms: the request continues to your handler.
6. 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`  |

The `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 through `CommonMiddlewareArgs`. 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](/server/facilitator) for how to create handlers.

```typescript theme={null}
import { createMiddleware } from "@faremeter/middleware/hono"

const middleware = await createMiddleware({
  x402Handlers: [solanaHandler, evmHandler],
  mppMethodHandlers: [mppChargeHandler],
  pricing: [
    { amount: "10000", asset: "USDC", recipient: "7xKX...", network: "solana:devnet" },
    { amount: "10000", asset: "USDC", recipient: "0x1234...", network: "eip155:84532" },
  ],
})
```

| 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.

```typescript theme={null}
import { createMiddleware } from "@faremeter/middleware/hono"

const middleware = await createMiddleware({
  facilitatorURL: "https://facilitator.corbits.dev",
  accepts: [
    // Payment requirements
  ],
  cacheConfig: {
    // Optional LRU cache settings
  },
})
```

| 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](/concepts/how-x402-works#protocol-versions). |

### Mixing remote x402 with in-process MPP

Use `createRemoteX402Handlers` to wrap a remote facilitator as in-process handlers, then combine with MPP handlers under a shared `pricing` config:

```typescript theme={null}
import { createMiddleware } from "@faremeter/middleware/hono"
import { createRemoteX402Handlers } from "@faremeter/middleware"

const x402Handlers = createRemoteX402Handlers({
  facilitatorURL: "https://facilitator.corbits.dev",
  accepts: [/* x402 payment requirements */],
})

const middleware = await createMiddleware({
  x402Handlers,
  mppMethodHandlers: [mppChargeHandler],
  pricing: [
    { amount: "10000", asset: "USDC", recipient: "7xKX...", network: "solana:devnet" },
  ],
})
```

## Defining payment requirements

Use `@faremeter/info` to construct payment requirements:

```typescript theme={null}
import { x402Exact } from "@faremeter/info/solana"

const accepts = [
  x402Exact({
    network: "devnet",
    payTo: "7xKXwxRPMo2sUAT5...",
    asset: "USDC",
    amount: "10000",
  }),
]
```

You can accept multiple payment methods by passing an array. The Solana `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:

```typescript theme={null}
import { x402Exact as solanaX402Exact } from "@faremeter/info/solana"
import { x402Exact } from "@faremeter/info/evm"

const accepts = [
  solanaX402Exact({ network: "devnet", payTo: "7xKX...", asset: "USDC", amount: "10000" }),
  x402Exact({ network: "base-sepolia", payTo: "0x1234...", asset: "USDC", amount: "10000" }),
]
```

## 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's `getRequirements` 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.

```typescript theme={null}
import {
  handleMiddlewareRequest,
  resolveSupportedVersions,
} from "@faremeter/middleware/common"
```

### 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`):

* `capture()`, `authorize()`, `paymentPayload`, `paymentRequirements`

**x402 v2 context** (`protocolVersion: 2`):

* `capture()`, `authorize()`, `paymentPayload`, `paymentRequirements`

**MPP context** (`protocolVersion: "mpp"`):

* `capture()`, `credential`, and an optional `authorize()`

Use `protocolVersion` to narrow the context type before accessing protocol-specific fields:

```typescript theme={null}
body: async (context) => {
  const result = await context.capture()
  if (!result.success) {
    return result.errorResponse
  }
  // Proceed to route handler
}
```

### Example: Hono with dynamic pricing

```typescript theme={null}
import { Hono, type MiddlewareHandler } from "hono"
import {
  handleMiddlewareRequest,
  resolveSupportedVersions,
} from "@faremeter/middleware/common"
import { createRemoteX402Handlers } from "@faremeter/middleware"
import { x402Exact } from "@faremeter/info/evm"

const dynamicPricing = (): MiddlewareHandler => {
  return async (c, next) => {
    const amount = c.req.query("amount") ?? "10000"

    const x402Handlers = createRemoteX402Handlers({
      facilitatorURL: "https://facilitator.corbits.dev",
      accepts: [
        x402Exact({
          network: "base-sepolia",
          asset: "USDC",
          amount,
          payTo: process.env.MERCHANT_ADDRESS,
        }),
      ],
    })

    return await handleMiddlewareRequest({
      x402Handlers,
      pricing: [
        { amount, asset: "USDC", recipient: process.env.MERCHANT_ADDRESS, network: "eip155:84532" },
      ],
      supportedVersions: resolveSupportedVersions(),
      resource: c.req.url,
      getHeader: (key) => c.req.header(key),
      sendJSONResponse: (status, body, headers) => {
        if (headers) {
          for (const [key, value] of Object.entries(headers)) {
            c.header(key, value)
          }
        }
        c.status(status)
        return c.json(body)
      },
      body: async (context) => {
        const result = await context.capture()
        if (!result.success) return result.errorResponse
        await next()
      },
    })
  }
}
```

See the [Dynamic Pricing recipe](/recipes/dynamic-pricing) for a complete multi-chain example with client code.

## Framework-specific guides

* [Express](/server/express) -- Express middleware setup.
* [Hono](/server/hono) -- Hono middleware setup.
* [Facilitator](/server/facilitator) -- Running your own facilitator.
