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

paycall-402

v0.1.1

Published

Umbrella package for Paycall 402 HTTP payment SDK packages.

Readme

Paycall 402

Framework‑agnostic HTTP 402 “payment required” protocol for monetizing API endpoints using EVM ERC‑20 authorizations.

Important: Currently, only EIP-3009 tokens are supported for end-to-end payment and settlement flows.

Packages

  • @paycall-402/types: shared protocol types
  • @paycall-402/utils: Base64URL(JSON) header helpers + crypto utilities
  • @paycall-402/core: PaymentEngine scheme registry + challenge creation + verification gates
  • @paycall-402/evm: EVM schemes (EIP‑3009, EIP‑2612) + client typed‑data builders
  • @paycall-402/server: createPaywall() + nonce stores + createPaywallWithEip3009Settlement (verify + relayer settlement)
  • @paycall-402/express: paywallCore() + paywall()
  • @paycall-402/client: fetch wrapper + axios interceptor + wallet abstraction

Examples

  • examples/servers/express: Express paywall demo server
  • examples/clients/node-paid-fetch: Node createPaidFetch with viem, ethers v6, and generic Wallet
  • examples/clients/injected-provider: Vite + MetaMask injected-provider demo

Protocol (headers)

  • X-PAYMENT-CHALLENGE: Base64URL(JSON PaymentChallenge) (server → client on 402; client must replay it on retry)
  • X-PAYMENT: Base64URL(JSON payment message) (client → server)
  • X-PAYMENT-SIGNATURE: 0x… EIP‑712 signature (client → server)

Header names are treated case‑insensitively (Node/Express expose them lowercased).

Install & build

pnpm install
pnpm build
pnpm test

After a clean checkout, workspace packages must be built before pnpm lint (declaration files live under each package’s dist/). Use pnpm build:packages or full pnpm build; CI builds packages before lint and test.

Maintainer release flow

# 1) add a changeset describing your package changes
pnpm changeset

# 2) apply lockstep version bumps and update internal package ranges
pnpm version-packages

# 3) publish to npm/GitHub Packages
pnpm release

Notes:

  • Packages are versioned in lockstep via Changesets fixed mode.
  • In this repo, unpublished @paycall-402/* packages use workspace:* so pnpm install and CI resolve local links. Published tarball dependency ranges are updated as part of the release/versioning workflow.

Server usage (Express, EIP-3009 + on-chain settlement)

import express from "express";
import { paywall } from "@paycall-402/express";

const app = express();

const chainId = 1;
const rpcUrl = "https://…";
const token = "0x…" as const; // EIP-3009-capable ERC-20
const recipient = "0x…";
app.get(
  "/premium",
  paywall({
    tokenAddress: token,
    evm: { chainId, network: "ethereum", rpcUrl },
    recipient,
    amountUsd: "1"
  }),
  (_req, res) => res.json({ ok: true })
);

Legacy paywallCore() + createPaywall() (multi-scheme, verify-only) remain available. See docs/executor.md for the settlement flow and status codes.

Client usage (fetch)

import { createPaidFetch, createEvmPaymentSigner, type Wallet } from "@paycall-402/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

const wallet: Wallet = {
  address: account.address,
  signTypedData: (td) =>
    account.signTypedData({
      domain: td.domain,
      types: td.types,
      primaryType: td.primaryType,
      message: td.message
    })
};

const paidFetch = createPaidFetch({
  wallet,
  signer: createEvmPaymentSigner({ rpcUrl: process.env.RPC_URL! })
});

const res = await paidFetch("http://localhost:4020/premium");
console.log(res.status, await res.text());

Client usage (axios)

import axios from "axios";
import { installAxiosPaymentInterceptor, createEvmPaymentSigner } from "@paycall-402/client";

const api = axios.create({ baseURL: "http://localhost:4020" });
installAxiosPaymentInterceptor({ axios: api, wallet, signer: createEvmPaymentSigner({ rpcUrl }) });
await api.get("/premium");

Security model (what’s enforced)

  • Nonce‑based replay protection: verified authorizations are written to a NonceStore; replays fail. With paywall (EIP-3009 settlement), the HTTP nonce is recorded only after a successful on-chain submit (503 + no nonce on settlement failure).
  • Double‑spend protection: NonceStore.set() must be atomic (Redis SET NX PX supported; InMemory throws on reuse).
  • Expiry validation: challenges are rejected when expired.
  • Balance preflight (optional): configure preVerify (for example createEvmErc20BalancePrecheck) to return 402 with error: "insufficient_funds" before signature verification when payer balance is too low.
  • EIP‑712 verification:
    • EIP‑3009: TransferWithAuthorization (domain uses chainId + verifyingContract, and name/version if readable)
    • EIP‑2612: Permit (requires reading the token nonces(owner) via RPC to ensure the signature matches the current nonce)
  • Chain ID validation: scheme instance enforces a single configured chainId.
  • Contract/token address validation: address format is validated; token is used as verifyingContract.
  • Amount validation: exact match with the server’s quoted amount.
  • Recipient validation: exact match with the server’s quoted recipient.

Running the example

# Terminal 1
cd examples/servers/express
CHAIN_ID=11155111 RPC_URL=https://... NETWORK=sepolia TOKEN=0x... RECIPIENT=0x... SCHEME=evm:eip3009 AMOUNT=1 RELAYER_PRIVATE_KEY=0x... pnpm dev

# Terminal 2
cd examples/servers/express
API_URL=http://localhost:4020 RPC_URL=https://... PRIVATE_KEY=0x... node ./src/client.ts

MetaMask frontend demo

# Terminal 1: start backend paywall server
cd examples/servers/express
CHAIN_ID=11155111 RPC_URL=https://... NETWORK=sepolia TOKEN=0x... RECIPIENT=0x... SCHEME=evm:eip3009 AMOUNT=1 RELAYER_PRIVATE_KEY=0x... pnpm dev

# Terminal 2: start browser demo
cd examples/clients/injected-provider
pnpm dev

Open http://localhost:5173, connect MetaMask, then call /premium. The frontend uses the connected wallet provider for reads by default; RPC URL is only an optional override.

On-chain settlement (EIP-3009)

See docs/executor.md. paywall submits the tx from your relayer, logs txHash, returns 503 if submission fails, and tracks receipts in the background (no blocking wait for confirmations in the HTTP handler).

Non‑goals

  • No hosted API product—this repo is libraries you import. Optional RabbitMQ/Kafka adapters are for your own workers.