npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@suverselabs/x402-server

v0.3.2

Published

x402 server middleware for Node.js (Express + Fastify). Issues 402 Payment Required challenges, verifies + settles via a remote facilitator, exposes the payment metadata to your handler.

Readme

@suverselabs/x402-server

npm license

Express and Fastify middleware that turns any HTTP route into a paid endpoint, settling stablecoin payments through a remote x402 facilitator (default: https://facilitator.suverse.io).

As of v0.3.0 the middleware auto-discovers network-specific infrastructure data (Solana feePayer, Cosmos grantee address, EVM EIP-712 USDC domain) from the facilitator's /supported endpoint and merges it into every 402 challenge — sellers configure only what they own (payTo, maxAmountRequired, scheme) and never need to know adapter-internal addresses.

client                middleware                 facilitator
  │                       │                            │
  ├── GET /paid ─────────▶│                            │
  │                       ├─ no X-Payment → 402 ─◀─────│
  │◀── 402 + challenge ───┤                            │
  │                       │                            │
  │ (signs USDC payment) │                            │
  │                       │                            │
  ├── GET /paid + X-Payment ▶│                         │
  │                       ├── POST /facilitator/verify ▶│
  │                       │◀────── { isValid: true } ──┤
  │                       ├── POST /facilitator/settle ▶│
  │                       │◀── { success:true, tx:0x.. }┤
  │◀── 200 + your handler ┤                            │

Install

npm install @suverselabs/x402-server
# Peer deps: install whichever you use
npm install express          # for the Express adapter
npm install fastify          # for the Fastify adapter

Express

import express from "express";
import { createExpressMiddleware } from "@suverselabs/x402-server/express";

const app = express();

app.use(
  "/paid",
  createExpressMiddleware({
    apiKey: process.env.SUVERSE_PAY_API_KEY!,
    facilitator: "https://facilitator.suverse.io",
    acceptedPayments: [
      {
        scheme: "exact",
        network: "eip155:8453",
        asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        payTo: "0xYourReceiveAddress",
        maxAmountRequired: "100000", // $0.10 USDC (6 decimals)
      },
    ],
    description: "Cool paid API",
  }),
);

app.get("/paid", (req, res) => {
  // req.x402Payment is populated by the middleware
  res.json({
    result: "data",
    payer: req.x402Payment?.payer,
    txHash: req.x402Payment?.txHash,
  });
});

app.listen(3000);

Fastify

import Fastify from "fastify";
import { createFastifyPreHandler } from "@suverselabs/x402-server/fastify";

const app = Fastify();

const x402 = createFastifyPreHandler({
  apiKey: process.env.SUVERSE_PAY_API_KEY!,
  facilitator: "https://facilitator.suverse.io",
  acceptedPayments: [
    {
      scheme: "exact",
      network: "eip155:8453",
      asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      payTo: "0xYourReceiveAddress",
      maxAmountRequired: "100000",
    },
  ],
});

app.post("/paid", { preHandler: x402 }, async (request) => {
  return { result: "data", payer: request.x402Payment?.payer };
});

await app.listen({ port: 3000 });

Options

| Option | Required | Default | Meaning | | --- | --- | --- | --- | | apiKey | yes | — | Resource API key from the Suverse Pay dashboard (sup_live_*). | | facilitator | yes | — | Base URL of the facilitator. | | acceptedPayments | yes | — | Non-empty array of { scheme, network, asset, payTo, maxAmountRequired }. | | description | no | — | Public text shown in the 402 challenge. | | x402Version | no | 2 | Protocol version to advertise. | | settle | no | true | If false, verify only (no on-chain settle). | | fetchImpl | no | global fetch | Inject your own fetch (testing, custom TLS). | | logger | no | silent | Pass a pino/winston-style logger for warn/error. | | disableAutoDiscover | no | false | Skip facilitator-extras auto-discovery; use only the extra you put on each accept entry (v0.2.0 behavior). | | facilitatorExtrasCacheTtlMs | no | 3_600_000 (1 h) | In-process TTL for the cached /supported response. |

Auto-discovery of per-kind extra (v0.3.0+)

The middleware calls GET ${facilitator}/facilitator/supported once at boot, caches the response per facilitator URL, and merges the per-kind extra into every 402 challenge it issues.

What lives in extra depends on the network:

| Network family | Auto-discovered fields | | --- | --- | | Solana | feePayer (the facilitator's co-signer pubkey) | | Cosmos | facilitator (grantee bech32), chainId, decimals, symbol | | EVM | name, version (EIP-712 USDC domain — emitted only by facilitators that publish it) |

This means a minimal x402 seller can ship a Solana endpoint with zero hardcoded infrastructure data:

acceptedPayments: [
  {
    scheme: "exact",
    network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
    asset: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    payTo: "MyMerchantSolanaAddress",
    maxAmountRequired: "70000",
    // No `extra: { feePayer: ... }` — facilitator fills it in.
  },
]

Merge precedence — seller wins

If you DO set extra on an accept entry, your values override the facilitator's per key:

extra: {
  name: "USD Coin",   // pinned by seller — wins
  version: "2",       // pinned by seller — wins
  // facilitator's other keys flow through (e.g. for compatibility shims)
}

This keeps pre-v0.3.0 configs working unchanged.

Failure mode

If the facilitator is unreachable, returns a non-200, or sends a body the middleware doesn't recognise, auto-discovery falls back silently to seller-only extra (matching v0.2.0 behavior). A warning is logged once per TTL window via opts.logger. The middleware never throws to your boot path because of an unreachable facilitator.

Explicit control

If you'd rather wire auto-discovery into your app's boot sequence yourself, set disableAutoDiscover: true and call the helpers directly:

import { warmFacilitatorCache } from "@suverselabs/x402-server";

await warmFacilitatorCache("https://facilitator.suverse.io");

Or read individual kinds:

import { getFacilitatorExtras } from "@suverselabs/x402-server";

const extra = await getFacilitatorExtras(
  "https://facilitator.suverse.io",
  "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
  "exact",
);
console.log(extra?.feePayer);

Receipt shape

After a successful payment the middleware attaches a PaymentReceipt to req.x402Payment (Express) / request.x402Payment (Fastify):

{
  payer: "0x09939648B56A776de9783eaE750A7fBE725761f1",
  network: "eip155:8453",
  asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  amount: "100000",
  txHash: "0xabc..." | null, // null in verify-only mode
  raw: { /* full facilitator response */ },
}

Errors

If the facilitator is unreachable or the payment payload is malformed, the middleware writes a 4xx/5xx JSON body with the x402 challenge included so a well-behaved client can immediately retry. The seller's handler is not invoked.

Wire-level errors thrown to your error handler are instances of X402Error — re-export from the root entry:

import { X402Error } from "@suverselabs/x402-server";

app.use((err, req, res, next) => {
  if (err instanceof X402Error) {
    /* log err.code, err.statusCode */
  }
  next(err);
});

Status

  • v0.3 (2026-05-30) — facilitator-extras auto-discovery + signers map consumption from /facilitator/supported. Sellers no longer need to hardcode extra per network.
  • v0.2 (2026-05-30) — x402 v2 ecosystem-client interop (Coinbase-flavour accepts shape, PAYMENT-SIGNATURE header).
  • v0.1 — Express + Fastify adapters. Verify + settle through any facilitator that implements the x402 v2 spec.
  • Python (FastAPI / Starlette / Flask) — next.

See CHANGELOG.md for the full history.

License

Apache-2.0