# @nerochain/x402-server

> Merchant middleware adapters for Express, Hono, Fastify, and Next.js.

`@nerochain/x402-server` is the merchant-side package. It wraps a normal HTTP handler with the x402 payment gate: 402 on missing payment, forwards the payload to the facilitator on retry, and attaches `PAYMENT-RESPONSE` on the eventual 200.

## Install

```bash
pnpm add @nerochain/x402-server
```

## Adapters

The package exports four adapters via subpath imports — choose the one that matches your framework:

```ts
import { x402Express } from "@nerochain/x402-server/express";
import { x402Hono }    from "@nerochain/x402-server/hono";
import { x402Fastify } from "@nerochain/x402-server/fastify";
import { x402Next }    from "@nerochain/x402-server/next";
```

All four take the same options object.

## Options

```ts
type X402ServerOptions = {
  paymentRequirements: PaymentRequirements | PaymentRequirements[];
  facilitator: { url: string; auth?: string };
  resource?: { url: string; description?: string; mimeType?: string };
  resourceUrl?: string;
  settleBeforeHandler?: boolean;
};
```

- **`paymentRequirements`** — what the merchant accepts. A single entry or an array of entries (multi-scheme or multi-asset).
- **`facilitator.url`** — the facilitator's base URL. The middleware will POST to `{url}/verify` and `{url}/settle`.
- **`facilitator.auth`** — optional bearer token, sent as `Authorization: Bearer <auth>` on facilitator requests.
- **`resource`** — descriptor included in the 402 body. Useful for documentation; not required.
- **`settleBeforeHandler`** — when `true`, the middleware settles before invoking the protected handler. Default `false` (handler runs first, then settle). The default lets the handler skip settlement on cache hits.

## Express example

```ts
import express from "express";
import { x402Express } from "@nerochain/x402-server/express";

const app = express();
app.use(express.json());

app.use(
  "/api/llm",
  x402Express({
    paymentRequirements: {
      scheme: "aa-native",
      network: "eip155:1689",
      amount: "1000",
      asset: USDT,
      payTo: MERCHANT,
      maxTimeoutSeconds: 60,
    },
    facilitator: { url: "https://facilitator.x402.nerochain.io" },
  }),
  (req, res) => {
    res.json({ ok: true, payer: req.x402Payer });
  },
);
```

After successful verification, `req.x402Payer` is populated with the SCW (or EOA, for `exact`) that paid for this request.

## Multi-scheme acceptance

```ts
paymentRequirements: [
  { scheme: "aa-native", network: "eip155:1689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
  { scheme: "exact",     network: "eip155:1689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
],
```

The client picks one entry to satisfy. The middleware verifies whichever scheme the client used.

## Paywall (browser-friendly 402 page)

For resources that are paid but also accessible from a browser (a paid article, a gated download), the package exposes a paywall variant that returns a styled HTML page on a 402 challenge when the request's `Accept` header includes `text/html`. Programmatic clients still receive the JSON body; the `PAYMENT-REQUIRED` header is preserved on both branches.

```ts
import express from "express";
import { x402ExpressPaywall } from "@nerochain/x402-server/paywall";

const app = express();
app.use(express.json());

app.use(
  "/api/article/:id",
  x402ExpressPaywall(
    {
      paymentRequirements: { ... },
      facilitator: { url: "https://facilitator.x402.nerochain.io" },
    },
    {
      title: "Pay to read this article",
      brandColor: "#000",
      playgroundUrl: "https://x402.nerochain.io/playground",
    },
  ),
  (req, res) => res.json({ content: "..." }),
);
```

The pure helpers are also exported for users assembling their own adapters:

```ts
import {
  isBrowserRequest,
  renderPaywallHtml,
  paywallizeRejection,
} from "@nerochain/x402-server/paywall";
```

`renderPaywallHtml(paymentRequired, options)` returns the full HTML document; `isBrowserRequest(headers)` is the `Accept`-header detector; `paywallizeRejection(rejection, headers, options)` turns a `GateRejection` into either the JSON or HTML response.

The page is self-contained — inline styles, no external CSS or JS, light + dark mode via `prefers-color-scheme`, and graceful degradation to the JSON 402 for any client without `Accept: text/html`.

## Programmatic core

If you're writing your own framework adapter, `@nerochain/x402-server` exposes the core directly:

```ts
import { gateRequest, settleAfterHandler } from "@nerochain/x402-server";

const gate = await gateRequest({ method, url, headers }, options);
if (gate.kind !== "proceed") return gate;          // 402 or 502 to send back
// run merchant handler...
const settled = await settleAfterHandler(gate, options);
if (settled.kind !== "ok") return settled;          // 502 to send back
// attach PAYMENT-RESPONSE header from settled.paymentResponseHeader, return 200
```

The four adapters are 30-50 line wrappers around this core. You can write a fifth for any framework that exposes a request/response interface.
