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

@zentpay/x402-pay

v0.2.12

Published

x402 payment SDK focused on gateway, payment session, recovery, and worker facilitator flows.

Readme

ZentPay SDK

@zentpay/x402-pay is the TypeScript SDK used by ZentPay Portal, the payment service, and developer integrations.

For public integration docs, see https://docs.zentpay.app.

Current Product Principle

ZentPay is built around one core payment experience:

One authorization, purchases from 0.01 USDC, and no gas required from the user.

Current product path:

Email login or wallet login
-> The user has USDC in their wallet
-> The user signs one budget authorization
-> The platform or relayer pays gas to relay or register that authorization
-> The user makes repeated small purchases
-> The backend charges USDC to the developer pay_to address through BudgetSpenderV2
-> ZentPay records charges and deliveries
-> The game or app fulfills the purchase

The current public SDK docs and examples describe the USDC Permit + BudgetSpender path.

Package Surfaces

import { createPaymentSession } from "@zentpay/x402-pay/client";
import { createInjectedWalletAdapter } from "@zentpay/x402-pay/wallet";
import { createPrivyEmbeddedWalletAdapter } from "@zentpay/x402-pay/wallet/privy";
import { zentpayExpress } from "@zentpay/x402-pay/server";

Main exports:

  • client: browser payment sessions, x402 payloads, USDC balance checks, BudgetSpender allowance checks, and permit helpers.
  • wallet: wallet adapter types and utilities.
  • wallet/injected: browser extension wallet adapter.
  • wallet/privy: Privy email embedded wallet adapter.
  • server: Express gateway helpers, Nakama fulfillment helpers, and Hosted ZentPay webhook and delivery helpers.
  • worker: Cloudflare Worker facilitator helpers.

The current server webhook, delivery, account handoff, trusted-server charge, and zentpay config CLI helpers require @zentpay/x402-pay 0.2.12 or newer. The published 0.2.11 package does not include createTrustedServerCharge:

npm install @zentpay/x402-pay@^0.2.12

The package also ships the zentpay CLI for Config-as-Code workflows:

npx zentpay init next --app gemix --env .env.local
npx zentpay config init --app gemix --file zentpay.config.json
npx zentpay auth browser --app gemix --scopes apps:read,apps:write,products:write,webhooks:write,runtime:write,keys:create --ttl 2h
npx zentpay config plan --file zentpay.config.json --mode merge --json
npx zentpay config apply --file zentpay.config.json --mode merge --yes --json
npx zentpay product create --app gemix --name "AI Usage" --price "$0.01" --pricing dynamic_order --min-amount "$0.01" --max-amount "$5.00"
npx zentpay order create --product zprod_... --amount "$0.37" --idempotency usage:user_123:req_456 --developer-user user_123 --json
npx zentpay price "$0.01"

Wallet Adapters

Privy Email Wallet

Use this adapter for low-friction email login.

Capabilities:

  • Prepare Privy email login.
  • Send an OTP.
  • Log in with an OTP.
  • Restore an authenticated Privy user.
  • Create a signer from the embedded wallet provider.

Privy CAPTCHA is managed in the Privy Dashboard. Do not pass your own Cloudflare Turnstile site key through .env; the adapter discovers the Privy public CAPTCHA site key and runs the invisible challenge internally before sendCode.

Browser Wallet

Use this adapter for users who already have a wallet and USDC.

Supported wallets can sign USDC Permit typed data. A plain approve() call is only a development diagnostic path because it requires the user to hold ETH for gas. It is not the normal user path.

BudgetSpender Client Helpers

Read BudgetSpender allowance:

const allowance = await session.getBudgetSpenderAllowance({
  spender: "0xb524F0b6b5e35d8b4c24455fcab0390c20Be0324",
});

Sign a USDC permit:

const result = await session.signBudgetSpenderPermit({
  spender: "0xb524F0b6b5e35d8b4c24455fcab0390c20Be0324",
  token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
  value: 1_000_000n,
  deadline: Math.floor(Date.now() / 1000) + 3600,
});

The active Base Sepolia spender is tracked in the deployment notes in ../contracts/README.md.

Server And Fulfillment

The server owns sensitive payment operations:

  • Submit USDC.permit(...).
  • Call BudgetSpenderV2.charge(payer, recipient, amount, chargeId).
  • Pay gas with the relayer or operator key.
  • Record authorizations, charges, deliveries, attempts, settlements, and webhooks in durable platform storage.
  • Trigger idempotent fulfillment after budget reservation or on-chain settlement.

For Nakama or other game backends, keep payment logic in the payment service. After ZentPay creates a durable delivery record, the payment service can call the game backend to fulfill the purchase.

Hosted ZentPay Helpers

External developer backends can import these helpers from @zentpay/x402-pay/server:

import {
  createTrustedServerCharge,
  createZentPayAccountHandoff,
  createIdempotencyKey,
  reconcileDelivery,
  verifyZentPayPaymentProof,
  verifyZentPayWebhookRequest,
  verifyZentPayWebhookSignature,
} from "@zentpay/x402-pay/server";
  • createZentPayAccountHandoff(): creates a short-lived handoff for the current game or app account. If an active binding and valid budget already exist, it returns a short-lived authorizationCode and accountConnectionId that can be used for the next purchase.
  • createIdempotencyKey(): creates a replay-safe key for a frontend purchase intent or backend order.
  • createTrustedServerCharge(): calls backend-only POST /api/charges with an app-scoped zpk_... key that has charges:create. Live products require a product-level trusted max; Dev Console and config-as-code default it to 1000000 atomic units, or 1 USDC.
  • verifyZentPayPaymentProof(): verifies the signed paymentProof JWS returned by trusted-server charges before immediate fulfillment. It pins the issuer to https://api.zentpay.app by default; pass expectedIssuer or jwksUrl only for local or test APIs you control. Store proof jti/proofId or the idempotencyKey in your fulfillment ledger and reject repeats; signature verification alone is not a replay cache.
  • verifyZentPayWebhookSignature(): verifies a webhook with the raw body, x-zentpay-timestamp, and x-zentpay-signature.
  • verifyZentPayWebhookRequest(): verifies Fetch Request objects, such as Next.js route handlers.
  • reconcileDelivery(): queries /api/deliveries/:deliveryId with a backend zpk_... API key as a fallback when a webhook is delayed.
const handoff = await createZentPayAccountHandoff({
  appSlug: "gemix",
  merchantUserId: "game-user-123",
  gameAccountLabel: "GemixPlayer#1234",
  returnUrl: "https://gemix.apps.zentpay.app/zentpay-auth-return?app=gemix",
  apiKey: process.env.ZENTPAY_API_KEY!,
});

if (handoff.status === "ready") {
  // Use handoff.authorization.authorizationCode for the next product route call.
}

For UI state endpoints, return a whitelist instead of the server-only authorization code:

import { toClientSafeAccountHandoff } from "@zentpay/x402-pay/server";

return Response.json(toClientSafeAccountHandoff(handoff));
const delivery = await reconcileDelivery({
  deliveryId: "ztdlv_...",
  apiKey: process.env.ZENTPAY_API_KEY!,
});
const charge = await createTrustedServerCharge({
  apiKey: process.env.ZENTPAY_API_KEY!,
  runtimeOrigin: "https://gemix.apps.zentpay.app",
  productSlug: "extra-moves-5",
  accountConnectionId: "ztconn_...",
  developerUserId: "game-user-123",
  idempotencyKey: createIdempotencyKey({
    scope: "gemix",
    parts: ["game-user-123", "extra-moves-5"],
  }),
});

const proof = await verifyZentPayPaymentProof({
  paymentProof: charge.paymentProof!,
  expected: {
    appId: process.env.ZENTPAY_APP_ID!,
    productId: process.env.ZENTPAY_PRODUCT_ID!,
    deliveryId: charge.deliveryId,
    idempotencyKey: charge.idempotencyKey,
    accountConnectionId: "ztconn_...",
    developerUserId: "game-user-123",
    amountAtomic: "30000",
    payTo: process.env.ZENTPAY_PAY_TO!,
    network: "eip155:84532",
  },
});

await grantOnce(proof.deliveryId, proof.idempotencyKey);

Only verify proofs returned by ZentPay APIs or passed through a server-side trusted path. Do not accept arbitrary client-supplied proof tokens without pinning the issuer/JWKS and all expected intent fields.

These helpers are server-only. Never bundle ZENTPAY_API_KEY or ZENTPAY_WEBHOOK_SECRET into browser, game client, or mobile app code. Portal login is the user's payment identity, not a developer backend. A real-money app still needs developer backend fulfillment, or a ZentPay-managed backend when that product is explicitly offered. Account Binding reuses a global wallet budget only after each app/game account has its own connection.

CLI / Agent Setup

The package also ships a zentpay CLI for developer setup and AI coding-agent workflows. Prefer browser or device authorization: the developer approves a short-lived, app-scoped CLI grant from Dev Console, and the agent receives only that grant.

zentpay auth browser --app gemix --scopes products:write,webhooks:write,keys:create,runtime:write,apps:read --ttl 2h
zentpay auth status --json
zentpay product diff --app gemix --file products.json
zentpay product upsert --app gemix --file products.json --match sku --json --yes
zentpay product create --app gemix --name "AI Usage" --price "$0.01" --pricing dynamic_order --min-amount "$0.01" --max-amount "$5.00"
ZENTPAY_API_KEY=zpk_... zentpay order create --product zprod_... --amount "$0.37" --idempotency usage:user_123:req_456 --developer-user user_123 --json
zentpay webhook upsert --app gemix --url https://game.example.com/api/zentpay/webhook --events payment.delivered
zentpay keys create --app gemix --label "Backend key" --scopes orders:create,orders:read,charges:create,deliveries:read,receipts:read,connections:create,connections:read --env .env.local
zentpay auth revoke

CLI grants are not admin tokens and cannot run settlement operations, recipient allowlist owner work, pay_to review, Portal listing review, or other ZentPay ops tasks. Backend API keys created by the CLI stay server-side. auth status verifies the saved grant against the API. config apply --json returns compact ops, ids, warnings, and one-time secrets by default; pass --verbose only for a full platform snapshot. keys pull writes comments for masked key previews, not a usable secret.

Testing Fixtures

Use @zentpay/x402-pay/testing for integration tests without touching the live API:

import {
  createZentPayMockFetch,
  createZentPayWebhookFixture,
  zentPayHandoffReadyFixture
} from "@zentpay/x402-pay/testing";

The fixtures include ready, needs-connection, needs-budget handoff states, signed payment.delivered webhook payloads, and a mock fetch handler for handoff, order, delivery, and health routes.

Where x402 Fits

x402 is a good fit for standard HTTP 402 payments. For one authorization and repeated in-app purchases, the core ZentPay path is Account Binding + USDC Permit + BudgetSpender.

Key differences:

  • exact: one exact payment for one request.
  • upto: a maximum payment for one request, not a reusable game budget.
  • BudgetSpender: reusable allowance for repeated small charges.

Development

cd sdk
npm run typecheck
npm run test
npm run build

Current package name:

@zentpay/x402-pay

The current product truth source is ../PRODUCT.md.