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

@bitaipay/pay402

v0.1.1

Published

BitAI Pay-402: a tiny SDK for paying (or charging for) an HTTP resource through BitAI Payment's HTTP-402 payment protocol.

Readme

BitAI Pay-402 — Developer Preview

A tiny SDK for paying (or charging for) an HTTP resource through BitAI Payment, using the standard HTTP 402 Payment Required status code. No agent-marketplace dependency, no BitAIcoin RPC, no channels — v1 settles instantly over BitAI Payment's own custodial ledger.

If you're integrating an agent that needs to pay for an API, or a service that wants to charge one, this is the whole surface you need. You do not need to understand BitAI Payment's internal services, database, or HTTP framework to use it.

Not Lightning's L402, not the x402 HTTP-USDC scheme. See Comparison to other 402 schemes in the full protocol doc for exactly how and why.

The flow, in one picture

 Agent (payer)                    Service (payee)                BitAI Payment
      |                                  |                              |
      | 1. GET /reports/q1               |                              |
      |--------------------------------->|                              |
      |                                  |                              |
      |         2. 402 + Challenge       |                              |
      |<---------------------------------|                              |
      |                                  |                              |
      | 3. POST /v1/authorizations (signed, as the payer)               |
      |----------------------------------------------------------------->
      |                                  |                              |
      |               4. { proof } (signed by BitAI Payment)            |
      |<-----------------------------------------------------------------
      |                                  |                              |
      | 5. GET /reports/q1                                              |
      |    X-Bitai-Pay402-Proof: <proof> |                              |
      |--------------------------------->|                              |
      |                                  | (verifies the proof offline, |
      |                                  |  no call to BitAI Payment)   |
      |          6. 200 + the resource   |                              |
      |<---------------------------------|                              |

Steps 1–2 and 5–6 are the standard HTTP-402 dance. Steps 3–4 are the one part specific to BitAI Pay-402: an instant, signed payment through BitAI Payment's ledger.

Install

npm install @bitaipay/pay402      # Node 18.17 or newer
import { Pay402Client } from "@bitaipay/pay402/client"; // payer (an agent that pays)
import { Pay402Guard, requirePay402Payment } from "@bitaipay/pay402/server"; // payee (a service that charges)

Try it against the public sandbox

A public developer-preview sandbox runs at https://pay402.bitaicoin.com.

Sandbox only. BAIC_TEST has no value. The sandbox runs on a single server with a single-node database: not highly available, may be reset, not a production service. Do not send it anything you cannot lose.

1. Generate a key pair. Your private key never leaves you; you share only the public key.

// keygen.mjs
import { generateKeyPairSync } from "node:crypto";
const { privateKey } = generateKeyPairSync("ed25519");
const jwk = privateKey.export({ format: "jwk" });
const hex = (b64url) => Buffer.from(b64url, "base64url").toString("hex");
console.log("PRIVATE_KEY_HEX=" + hex(jwk.d)); // secret: keep it
console.log("PUBLIC_KEY_HEX=" + hex(jwk.x)); //  send this one

2. Get registered. Sandbox access is operator-managed for now (there is deliberately no public registration endpoint). Send the maintainer a principal id (3-40 characters: lowercase letters, digits, hyphens) and your PUBLIC_KEY_HEX, once for a payer and once for a payee if you are also running a service. A payer is credited a small BAIC_TEST balance.

3. Run a paid request. A payee service and a payer, using only the documented API:

// service.js  (payee: charges 0.01 BAIC_TEST for /reports/:quarter)
import Fastify from "fastify";
import { Pay402Guard, requirePay402Payment } from "@bitaipay/pay402/server";

const app = Fastify();
const guard = new Pay402Guard({
  payeePrincipalId: process.env.PAYEE_PRINCIPAL_ID,
  bitaiPaymentUrl: "https://pay402.bitaicoin.com",
});

app.get(
  "/reports/:quarter",
  {
    preHandler: requirePay402Payment(guard, (request) => ({
      resourceRef: `GET /reports/${request.params.quarter}`,
      amountSatoshis: 1_000_000n,
    })),
  },
  async (request, reply) => {
    reply.send({ quarter: request.params.quarter, revenue: "$1,234,567" });
  },
);

await app.listen({ port: Number(process.env.PORT ?? 3000), host: "127.0.0.1" });
console.log("READY");
// payer.js  (payer: pays the 402 and prints the resource)
import { Pay402Client, Pay402ClientError } from "@bitaipay/pay402/client";

const client = new Pay402Client({
  principalId: process.env.PAYER_PRINCIPAL_ID,
  privateKey: Buffer.from(process.env.PAYER_PRIVATE_KEY_HEX, "hex"),
});

try {
  const result = await client.fetchProtected(`${process.env.SERVICE_URL}/reports/q1`);
  console.log(JSON.stringify({ ok: true, paid: result.paid, body: await result.response.json() }));
} catch (error) {
  if (error instanceof Pay402ClientError) {
    console.log(JSON.stringify({ ok: false, code: error.code, message: error.message }));
    process.exit(1);
  }
  throw error;
}
npm install @bitaipay/pay402 fastify
PAYEE_PRINCIPAL_ID=<your-payee-id> node service.js                     # terminal 1
SERVICE_URL=http://127.0.0.1:3000 PAYER_PRINCIPAL_ID=<your-payer-id> \
  PAYER_PRIVATE_KEY_HEX=<your-private-key> node payer.js               # terminal 2

An unfunded payer gets INSUFFICIENT_BALANCE. That is expected, and is handled below.

10-minute integration example

If you're the payer (an agent that needs to pay for an API)

import { Pay402Client } from "@bitaipay/pay402/client";

const client = new Pay402Client({
  principalId: "agent-abc123",       // your INDIVIDUAL principal id, provisioned with BitAI Payment
  privateKey: myEd25519PrivateKey,   // the key that principal was registered with
});

const result = await client.fetchProtected("https://api.example.com/reports/q1");
if (result.response.ok) {
  const report = await result.response.json();
}

That's it. If the resource costs nothing (no 402), fetchProtected behaves exactly like fetch. If it costs something, the SDK pays it, verifies BitAI Payment's proof, and retries automatically.

Handle payment-specific failures with Pay402ClientError:

import { Pay402Client, Pay402ClientError } from "@bitaipay/pay402/client";

try {
  await client.fetchProtected(url);
} catch (error) {
  if (error instanceof Pay402ClientError) {
    switch (error.code) {
      case "INSUFFICIENT_BALANCE":
        // top up and retry
        break;
      case "CHALLENGE_EXPIRED":
        // the 402 was stale; request the resource again for a fresh one
        break;
      case "ALREADY_PAID_BY_OTHER":
        // a race with another payer for the same reference -- rare, safe to retry with a fresh request
        break;
      default:
        throw error;
    }
  } else {
    throw error;
  }
}

See Pay402ClientErrorCode for the full list.

If you're the payee (a service that wants to charge for an endpoint)

Using Fastify:

import { Pay402Guard, requirePay402Payment } from "@bitaipay/pay402/server";

const guard = new Pay402Guard({
  payeePrincipalId: "service-xyz789", // your INDIVIDUAL principal id
  bitaiPaymentUrl: "https://pay402.bitaicoin.com", // the sandbox; use your own deployment later
});

app.get(
  "/reports/:quarter",
  {
    preHandler: requirePay402Payment(guard, (request) => ({
      resourceRef: `GET /reports/${request.params.quarter}`,
      amountSatoshis: 1_000_000n, // 0.01 BAIC_TEST
    })),
  },
  async (request, reply) => {
    // Only reached once a valid, unredeemed proof was presented.
    reply.send({ quarter: request.params.quarter, revenue: "$1,234,567" });
  },
);

Pay402Guard itself has no Fastify dependency — requirePay402Payment is a ~20-line adapter (sdk/server/fastify-pay402.ts) you can copy and rewrite for Express, Koa, or a raw http.Server in a few minutes; see Framework independence.

Run the reference application (from a clone of the repo)

pnpm exec tsx sdk/reference-app/run.ts

Boots a real BitAI Payment instance, a real reference resource server, and a real payer agent, all talking real HTTP, and prints every step. No external services required (PGlite in-process; BitAI Pay-402 never touches BitAIcoin at all).

Where to go next

  • docs/PROTOCOL.md — the full spec: Challenge and Proof schemas, trust model, security/replay model, and how this differs from Lightning's L402 and the x402 HTTP-USDC scheme.
  • client/ — the payer-side SDK.
  • server/ — the payee-side SDK (framework-agnostic core + a Fastify adapter).
  • reference-app/ — the minimal working example above, in full.
  • test/pay402-sdk.test.ts — the SDK's own hard acceptance test, covering every failure mode listed above against real HTTP servers.