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

@seedhape/x402-merchant-sdk

v0.5.2

Published

Add x402 payment-gated routes, settlement receipts, and merchant accounting to Node.js services.

Readme

@seedhape/x402-merchant-sdk

One catalog for agent commerce

Use createMerchantCommerce to define products once. The same product definitions can feed the SDK's current x402 paywall and future ACP/UCP/MPP adapters; merchants do not maintain protocol-specific catalogs.

const commerce = createMerchantCommerce({
  paywall: { payTo, ...base, facilitator: base.facilitator },
  products: [{
    id: "weather", name: "Weather API", description: "Current weather",
    endpoint: "/weather",
    price: { amount: 50_000n, ...base },
  }],
});

commerce.catalog();       // publish to your agent-facing catalog
commerce.paywallFor("weather"); // pass to existing paywall middleware

The helper normalizes discovery metadata and product lookup. Fulfillment and refunds remain merchant-owned and should use the purchase ID as their durable idempotency key.

Unified seller facade (preview)

createSeedhapeSeller is the single-drop-in entry point for a server-side Express route. Define each product once and keep provider credentials in the server environment:

import { base, createSeedhapeSeller } from "@seedhape/x402-merchant-sdk";

const seller = createSeedhapeSeller({
  products: [{
    id: "weather",
    name: "Weather API",
    description: "Current weather data",
    endpoint: "/weather",
    price: "0.50",
    fulfill: async () => ({ temperature: 24 }),
  }],
  payments: {
    x402: {
      payTo: process.env.MERCHANT_WALLET!,
      network: base.network,
      asset: base.asset,
      decimals: base.decimals,
      facilitator: base.facilitator,
    },
    stripeMpp: {
      stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
      profileId: process.env.STRIPE_PROFILE_ID!,
      mppSecretKey: process.env.MPP_SECRET_KEY!,
    },
  },
});

app.all("/weather", seller.route("weather"));

The facade preserves the existing x402 Bazaar discovery challenge. It selects Stripe MPP when a client advertises the MPP payment scheme and selects x402 otherwise. ACP/UCP checkout remains a separate integration gate; it will consume the same catalog rather than requiring another merchant catalog or middleware stack.

Add an x402 payment gate to an existing Express, Hono, or node:http service. The SDK returns a standard 402 Payment Required challenge, verifies the buyer's payment through an x402 facilitator, settles USDC directly to the merchant wallet, and exposes a receipt for your application ledger.

Install

npm install @seedhape/x402-merchant-sdk

Stripe machine payments (MPP)

Install the optional MPP runtime when you want agents to pay with Stripe cards or Shared Payment Tokens:

npm install mppx

Create one Stripe MPP paywall per seller endpoint. The seller keeps the Stripe secret key and profile_test_... profile ID on the server; the SDK returns the payment challenge and settles the credential without exposing either value:

import { createStripeMppPaywall } from "@seedhape/x402-merchant-sdk";

const mpp = await createStripeMppPaywall({
  stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
  profileId: process.env.STRIPE_PROFILE_ID!,
  mppSecretKey: process.env.MPP_SECRET_KEY!,
  amount: "0.50",
  currency: "usd",
  description: "Weather API request",
});

export async function weather(request: Request) {
  return mpp.handle(request, async () =>
    Response.json({ temperature: 24, conditions: "clear" }),
  );
}

An unpaid agent receives HTTP 402; a valid credential is verified and settled before the fulfillment callback runs. For a Stripe Connect direct charge, pass connect: { stripeAccount: "acct_..." }. To enable Stripe's stablecoin MPP rail as well, supply a Stripe SDK client and a test Tempo deposit address. Use profile_test_... and sk_test_... in a Stripe Sandbox.

Express

import express from "express";
import { base, expressPaywall, merchantConfig } from "@seedhape/x402-merchant-sdk";

const app = express();

app.use(expressPaywall(merchantConfig(base, {
  payTo: "0xYourBaseMerchantWallet",
  paymentMethods: ["eip3009", "erc7710"],
  price: ({ path }) => path === "/weather"
    ? { amount: 50_000n, ...base }
    : null,
  free: ["/health", "/docs/*"],
  facilitator: { url: process.env.FACILITATOR_URL! },
  route: {
    name: "Weather API",
    description: "Current weather data",
    category: "weather",
    inputSchema: { type: "object", properties: { city: { type: "string" } } },
    outputSchema: { type: "object" },
  },
  receipts: { record: async (receipt) => db.receipts.insert(receipt) },
})));

app.get("/weather", (req, res) => {
  res.json({ temperature: 24, conditions: "clear", receipt: req.x402Receipt?.id });
});

price may be a fixed Money object or a resolver based on the request path, method, and query. Return null for a free route. USDC amounts are integer base units: 50_000n is 0.05 USDC.

Network presets and payment methods

Use base, baseSepolia, solana, or solanaDevnet to preconfigure the CAIP-2 network, USDC mint/contract, decimals, and default facilitator:

import { baseSepolia, expressPaywall, merchantConfig } from "@seedhape/x402-merchant-sdk";

app.use(expressPaywall(merchantConfig(baseSepolia, {
  payTo: "0xYourStagingWallet",
  paymentMethods: ["eip3009"],
  price: ({ path }) => path === "/weather"
    ? { amount: 10_000n, ...baseSepolia }
    : null,
})));

paymentMethods defaults to ['eip3009'], the broadly supported payment method. Set ['eip3009', 'erc7710'] to let the buyer/client choose both methods. Only advertise ERC-7710 when the configured facilitator supports it. If the methods use different facilitators, configure facilitators: { eip3009: {...}, erc7710: {...} }; the SDK selects the facilitator matching the buyer's selected method.

Base and Solana on one route

Use accepts to expose both chains from the same resource. Bazaar and downstream catalogs such as Agentic Market treat these as payment choices on one service listing:

import { base, solana, expressPaywall, merchantConfig } from "@seedhape/x402-merchant-sdk";

// Create cdpFacilitator with createCdpFacilitatorClient as shown below.

app.use(expressPaywall(merchantConfig(base, {
  accepts: [{
    ...base,
    payTo: process.env.BASE_MERCHANT_WALLET!,
    paymentMethods: ["eip3009"],
  }, {
    ...solana,
    payTo: process.env.SOLANA_MERCHANT_WALLET!,
    feePayer: process.env.SOLANA_FEE_PAYER!,
  }],
  price: { amount: 10_000n, ...base },
  facilitator: {
    url: "https://api.cdp.coinbase.com/platform/v2/x402",
    client: cdpFacilitator,
  },
  route: {
    name: "Market Data",
    description: "Paid market data on Base or Solana",
    inputSchema: { type: "object", properties: { symbol: { type: "string" } } },
    outputSchema: { type: "object" },
  },
})));

feePayer is the Solana facilitator signer advertised by its /supported response; it is not the merchant wallet. Use a facilitator that supports every advertised network, or set a per-option facilitator. Solana payments use the official x402 exact SVM scheme and a base64-encoded, partially signed versioned transaction in PAYMENT-SIGNATURE.

The built-in Solana mainnet preset uses solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp and native USDC mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v. Solana addresses are case-sensitive. Its default facilitator is https://facilitator.payai.network; the devnet preset uses the test-only https://x402.org/facilitator.

Browser wallet paywall

Install the optional official UI when people should be able to open the paid route directly and pay with an EVM or Solana browser wallet:

npm install @seedhape/x402-merchant-sdk @x402/paywall react react-dom

Then enable it on the same configuration:

const config = merchantConfig(base, {
  accepts: [
    { ...base, payTo: process.env.BASE_MERCHANT_WALLET! },
    {
      ...solana,
      payTo: process.env.SOLANA_MERCHANT_WALLET!,
      feePayer: process.env.SOLANA_FEE_PAYER!,
    },
  ],
  price: { amount: 10_000n, ...base },
  browserPaywall: {
    appName: "Market Data",
    appLogo: "https://api.example.com/icon-512.png",
    testnet: false,
  },
  facilitator: { url: "https://facilitator.payai.network" },
});

Express, Hono, and node:http adapters now return the official @x402/paywall HTML when the request accepts text/html. Programmatic callers continue receiving the normal JSON challenge and PAYMENT-REQUIRED header. The UI registers both official evmPaywall and svmPaywall handlers. Because @x402/paywall is an optional peer dependency, API-only installations do not pull its browser-wallet and React dependency tree.

Coinbase CDP Facilitator and Bazaar

For Coinbase Bazaar indexing, use Coinbase's authenticated facilitator client rather than passing the CDP API secret as a bearer token:

npm install @coinbase/cdp-sdk
import { createCdpFacilitatorClient } from "@coinbase/cdp-sdk/x402";

const cdpFacilitator = createCdpFacilitatorClient({
  apiKeyId: process.env.CDP_API_KEY_ID!,
  apiKeySecret: process.env.CDP_API_KEY_SECRET!,
});

const config = merchantConfig(base, {
  payTo: process.env.MERCHANT_WALLET!,
  facilitator: {
    url: "https://api.cdp.coinbase.com/platform/v2/x402",
    client: cdpFacilitator,
  },
  price: { amount: 10_000n, ...base },
  route: {
    name: "Link Lens URL Inspector",
    description: "Extract metadata and readable text from a public URL.",
    inputSchema: { type: "object", properties: { url: { type: "string", format: "uri" } }, required: ["url"] },
    outputSchema: {
      type: "object",
      properties: { title: { type: "string" }, text: { type: "string" } },
      required: ["title", "text"],
    },
    outputExample: { title: "Example page", text: "Readable page text" },
    tags: ["web", "metadata", "extraction"],
    iconUrl: "https://api.example.com/icon-512.png",
  },
});

Set CDP_API_KEY_ID and CDP_API_KEY_SECRET on the server only. The SDK uses the injected client for official EIP-3009 verification and settlement; the existing URL/API-key configuration remains available for other facilitators and custom ERC-7710 endpoints. After deployment, validate the endpoint and complete one successful payment through CDP for Bazaar indexing.

Do not treat FACILITATOR_URL=https://api.cdp.coinbase.com/platform/v2/x402 by itself as CDP authentication, and do not send CDP_API_KEY_SECRET as a raw bearer token. Use createCdpFacilitatorClient() so the CDP SDK creates the required authenticated facilitator requests.

Bazaar publication checklist

  1. Deploy the route at a public HTTPS URL.

  2. Include route metadata and accurate input/output schemas so the SDK emits extensions.bazaar.

  3. Validate the endpoint before paying:

    curl -X POST https://api.cdp.coinbase.com/platform/v2/x402/validate \
      -H "Content-Type: application/json" \
      -d '{"resource":"https://api.example.com/report","method":"GET"}'

    Continue only when the response reports valid: true and an accepted simulation outcome.

  4. Complete one successful payment through the CDP Facilitator. There is no separate Bazaar registration form or publish API. CDP indexes the endpoint after settlement; indexing may initially report processing and become searchable asynchronously.

  5. Confirm the facilitator extension response reports Bazaar success or processing, then search the CDP Bazaar catalog for the resource.

The route metadata automatically becomes the Bazaar extensions.bazaar.info object and populates the resource serviceName and tags fields in the x402 v2 challenge. Use outputExample because agents use a realistic result example when deciding whether to call a service. Sonar can read the same resource URL, description, schemas, payment requirements, network, asset, and payment methods from that challenge.

iconUrl is copied into the resource and Bazaar metadata for downstream marketplaces such as Agentic Market. Use a publicly accessible HTTPS image URL, preferably a square PNG or WebP without authentication.

When deploying behind a TLS reverse proxy, set publicOrigin so the resource URL advertises the public HTTPS origin while preserving request paths and query parameters:

publicOrigin: "https://api.example.com",

Hono and node:http

Use honoPaywall(config) with Hono or nodePaywall(config) for a raw Node server. All adapters use the same PaywallConfig and facilitator contract.

HTTP and MCP together

One merchant can expose the same service through both an HTTP API and an MCP tool. Reuse the network, USDC asset, recipient, facilitator, and receipt sink, then register a paid MCP tool with the official @x402/mcp wrapper:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { base, createPaidMcpTool, merchantConfig } from "@seedhape/x402-merchant-sdk";

const config = merchantConfig(base, {
  payTo: process.env.MERCHANT_WALLET!,
  price: { amount: 50_000n, ...base },
  route: { name: "Market Data", description: "Paid market data" },
  receipts: { record: async (receipt) => db.receipts.insert(receipt) },
});

const mcp = new McpServer({ name: "market-data", version: "1.0.0" });
await createPaidMcpTool(mcp, config, {
  name: "get_market_data",
  description: "Get paid market data",
  inputSchema: { symbol: z.string() },
  inputJsonSchema: {
    type: "object",
    properties: { symbol: { type: "string" } },
    required: ["symbol"],
  },
}, async ({ symbol }) => ({ symbol, price: 24812.05 }));

The HTTP route and MCP tool produce separate x402 resources, so each can have its own price and discovery URL while sharing the same merchant wallet and facilitator.

Optional AP2 Checkout JWT

Enable AP2 on an HTTP paywall to issue a signed merchant Checkout JWT with every unpaid or rejected 402 response. The SDK returns it in the AP2-CHECKOUT-JWT header; this does not change x402 verification or settlement.

AP2 is optional. A route without the ap2 option behaves exactly like a normal x402 route. AP2 adds signed checkout context for AP2-aware buyers and agents; the facilitator still verifies and settles the EIP-3009 or ERC-7710 payment. The current Checkout JWT binds one network, so SDK routes using ap2 must configure a single payment option; multi-network Solana AP2 mandates are a separate follow-up.

app.use(expressPaywall(merchantConfig(base, {
  payTo: process.env.MERCHANT_WALLET!,
  price: { amount: 50_000n, ...base },
  ap2: {
    issuer: "https://api.example.com",
    privateKeyPem: process.env.MERCHANT_AP2_PRIVATE_KEY_PEM!,
    keyId: "merchant-ap2-1",
    merchantId: "weather-api",
    merchantName: "Example Weather",
    merchantWebsite: "https://example.com",
    expiresInSeconds: 300,
  },
  route: { name: "Weather API", description: "Current weather data" },
})));

Store the configuration in the server environment:

MERCHANT_AP2_ISSUER=https://api.example.com
MERCHANT_AP2_KEY_ID=merchant-ap2-1
MERCHANT_AP2_PRIVATE_KEY_PEM="-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----"

Generate an ES256 PKCS#8 key with OpenSSL:

openssl ecparam -name prime256v1 -genkey -noout -out ap2-private.pem
openssl pkcs8 -topk8 -nocrypt -in ap2-private.pem -out ap2-private-pkcs8.pem

Load the PEM as one environment variable, replacing line breaks with \\n, or load it from your deployment secret manager. Never expose the private key in browser code, a client bundle, or a public repository.

The JWT includes the merchant, resource, product, price, currency, payout address, network, issuer, issue time, and expiry. It is returned only on unpaid or rejected 402 responses:

HTTP/1.1 402 Payment Required
AP2-CHECKOUT-JWT: eyJ...
PAYMENT-REQUIRED: eyJ...

createAp2CheckoutJwt() is also exported for custom transports. MCP integrations can use this helper when their transport exposes an equivalent challenge metadata field. The SDK does not require merchants to implement AP2 payment settlement separately.

Payment flow

  1. An unpaid request receives a v2 402 challenge with a PAYMENT-REQUIRED header containing one or more accepted networks, recipient wallets, USDC assets, the amount, and resource URL.
  2. The buyer selects an accepted option, creates an EVM authorization or Solana transaction, and sends it in PAYMENT-SIGNATURE.
  3. The facilitator verifies and settles the payment.
  4. USDC settles directly to payTo; Seedhape never holds merchant funds.
  5. The request continues and the settlement is returned in PAYMENT-RESPONSE.

The SDK emits the current x402 v2 challenge shape. For migration, it also accepts legacy X-PAYMENT requests and exposes X-PAYMENT-RESPONSE alongside the v2 response header.

Official x402 integrations

The SDK is built on the official @x402/core, @x402/evm, and @x402/svm packages. EIP-3009 and exact-SVM verification and settlement use x402ResourceServer, HTTPFacilitatorClient, and the official chain scheme. Bazaar declarations use @x402/extensions/bazaar and are registered with the resource server.

ERC-7710 remains an opt-in Seedhape facilitator method because the official EVM exact server currently covers EIP-3009 and Permit2, not ERC-7710. When erc7710 is selected, the SDK routes it to the configured facilitator override; it never silently sends an ERC-7710 payload through the EIP-3009 verifier.

Unpaid responses also include this developer notice:

This resource is protected by the x402 payment protocol.

Note to developers: install @x402/paywall to enable the in-browser wallet connection and payment UI. Programmatic clients should read the payment requirements from the 402 response headers and JSON body.

Bazaar discovery

Bazaar is an optional discovery layer. Add Bazaar discovery metadata to your x402 route when using an x402 resource server/facilitator that supports the Bazaar extension. Describe the input schema, route, method, and response so agents can find the service without a hardcoded URL. Bazaar does not change settlement or custody.

Sonar discovery

Sonar is Seedhape's service discovery surface for merchants and agents. After deploying your x402 endpoint, list it in Sonar with its public URL, HTTP method, service description, input schema, price, token, network, receiving wallet, and supported payment methods. Sonar helps agents discover and evaluate the service; it does not custody funds or settle payments. The x402 paywall and facilitator still perform verification and settlement.

Sonar listing does not replace Bazaar metadata. A merchant can publish Bazaar discovery metadata for the open x402 ecosystem and list the same endpoint in Sonar for Seedhape discovery.

Production checklist

  • Use a self-custodial merchant receiving address.
  • Use Base mainnet or Solana mainnet presets in production and their testnet/devnet presets only for testing.
  • Configure a production facilitator URL and keep it server-side.
  • Keep health, documentation, and discovery metadata routes free.
  • Record the receipt ID, resource, payer, amount, network, and transaction hash.
  • Treat payTo, asset, network, and resource as server-controlled values; never accept them from the buyer.

Publishing and full integration guide

Authenticate and verify the package:

npm login
npm whoami
npm run typecheck
npm run build:packages
npm pack --dry-run --workspace=@seedhape/x402-merchant-sdk

Publish the public scoped package:

npm publish --workspace=@seedhape/x402-merchant-sdk --access public

For local tarball testing, versioning, Bazaar metadata, and the complete release checklist, see the repository guide:

docs/SDK-PUBLISHING-GUIDE.md

License

MIT