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

@paybox-sh/sdk

v2.8.0

Published

Typed Node SDK + `paybox` CLI for the PayBox agent API, with REST core operations and runtime MCP plugin discovery and invocation.

Readme

@paybox-sh/sdk

Typed Node SDK and paybox CLI for the PayBox agent API. It mirrors the MCP tool surface — list_credentials, request_payment, claim_payment_credentials, request_wallet_sign, request_secret, request_swap, request_transfer, discover_services, pay_x402, use_service, get_portfolio, get_buy_link, get_deposit_link, request_account_change, get_request, and the generic plugin discovery, contract, and invocation flow. Core operations use the REST API; plugins use the same MCP tools as connector hosts, with no hardcoded per-plugin paths.

Wallet signing is non-custodial and runs in-process: the SDK reuses the exact signing core from the wallet-sign iframe (@paybox/mcp-app), builds the chain digest, and ed25519-signs the MoonX envelope with your pbxk1. key. The MoonX secret never reaches the client — the secret-gated /sign happens server-side.

Install

pnpm add @paybox-sh/sdk      # library
npx @paybox-sh/sdk login     # or use the CLI directly

Driving this CLI from an agent? SKILL.md ships in the package and routes wallet tasks through existing access or the required setup steps. It preserves an explicit wallet choice and resumes the requested task after setup. Use the CLI on Muse, Grok Bot, Grok Computer, and any agent on a computer with no connector screen — not the grok.com MCP connector path. Install it where the agent runs, including a hosted VM or sandbox.

CLI

# Setup is two commands. `login` authenticates; `connect` pairs a signing key.
# Pairing prints a two-digit number and a link; you open the link and pick that
# same number in PayBox. The key is generated locally and never leaves this
# machine, so there is nothing to copy. Neither command needs a browser on the
# machine running the CLI — approve both from a phone if you like. Add --no-open
# to either command to print the link without launching a browser.
paybox login                              # device-code OAuth (browser + passkey)
paybox login --key pbx_live_…             # personal API key instead (no OAuth)
paybox connect                            # pair a signing key
PAYBOX_SIGNING_KEY=pbxk1.… paybox …       # headless: reuse an already-paired key

paybox credentials                        # list usable credentials
# `--credential <id>` below is the `credential.id` from that list, not the wallet name.
paybox pay --credential <id> --merchant Acme --url https://acme.com --amount 1999
paybox secret --credential <id> --purpose "deploy"        # one-time token
paybox secret --credential <id> --raw                     # raw value (grant-gated)
paybox sign --credential <id> --intent '{"op":"message","message":"gm"}'
paybox swap --credential <id> --src-chain eip155:8453 \
  --src-token native --dst-token 0x… --amount 1000000000000000
paybox transfer --credential <id> --chain eip155:8453 \
  --to 0x… --token 0x… --amount 1000000   # omit --token for ETH or SOL
paybox portfolio --address 0x… --networks 1,8453
paybox discover "weather api"             # browse curated paid x402 services
paybox discover --raw "weather api"       # debug: uncurated compact summaries
paybox pay-x402 --credential <id> --url https://svc/api --accepts @accepts.json
paybox use-service --credential <id> --url https://svc/api   # paybox pays + fetches
paybox claim <request_id>                 # claim an approved payment's card (one-time)
paybox buy-link --credential <id> --amount-usd 50   # defaults EVM funding to Base
paybox buy-link --credential <id> --destination eip155:1 --currency eth
paybox account-change --note "need a wallet grant"  # manage_url for the user to open
paybox account-change --credential <id> --mode always_approve  # user confirms the new approval mode
paybox request <request_id> --wait        # poll a pending request
paybox request <request_id> --complete-signature  # sign that parked wallet-sign request locally

# Plugins (enable them in the paybox app first)
paybox plugins list --status enabled
paybox plugins contract paybox://plugins/world
paybox plugins use world world_get_events --input '{"status":"active"}'

paybox version                            # installed version (+ update check)
paybox update                             # update the global install to latest
paybox uninstall                          # clear stored config (prints npm rm)

paybox --json credentials                 # machine-readable output on any command

version/update/uninstall are conveniences over npm: update runs npm i -g @paybox-sh/sdk@latest against the same registry version checks (use --print to just show it); uninstall clears ~/.config/paybox and prints the npm rm -g line (a package can't remove its own binary). For project installs use pnpm up/pnpm rm, or npx @paybox-sh/sdk@latest to always run the latest without installing.

A global install also updates itself: at most once a day, before a command, the CLI checks npm. When a newer version in the same major exists, it installs it, prints one line to stderr, and runs the same command again with the new version. Stdout does not change. Project installs, npx, and new major versions get a stderr notice instead. Set PAYBOX_NO_AUTO_UPDATE=1 to turn it off.

sign, swap, transfer, pay-x402, and use-service can complete in-process with a configured pbxk1. key. Plugin calls return the raw MCP tool result. paybox plugins use declares the browser signing surface, so its output has no in-chat signing-window fields. A parked plugin trade finishes from the CLI through the completion_url returned when the wallet's access is "Complete transactions in PayBox". usePlugin(args, "browser") declares the same surface from the library.

An MCP host can declare its signing surface on each HTTP request with X-Paybox-Signing-Surface: in-process, browser, or none. Omit the header to keep the existing MCP Apps behavior. The value selects one advisory next_action; it does not grant signing access. A host must use in-process only when it has an eligible local callback for that operation. For a parked wallet-sign request, call paybox.completeWalletSignRequest(requestId) from that callback. The SDK reads the stored intent from PayBox and signs the same request. It does not create another request. Do not put the signing key in an MCP tool argument or model context. pending_approval still needs a person; denied and error remain terminal request states.

For a Solana swap or transfer the SDK re-pins a fresh recent blockhash immediately before signing (parity with the signing window — the quote-time blockhash expires within ~60–90s, often before signing), so a swap that dwells for approval no longer broadcasts as BlockhashNotFound. An EVM swap that needs a new token approval signs the approval, waits for it to confirm, and then signs the swap step of the same request.

pay-x402 is header mode — on success output.value.x_payment is the X-PAYMENT header to replay on the original request. use-service is gateway mode — PayBox makes the paid call for you and returns the resource's reply on output.value.response. Pass --accepts from the resource's own 402.

A paybox discover result with accepts: [] has no catalog price: the provider sets it in the live 402, or the route is free. Read it with paybox plugins contract <contract_uri> and call it with use-service and that contract's --method and --body; PayBox reads the live 402 and pays within the grant. If use-service reports HTTP 200 instead of 402, the route is free: call it directly with the same method and body.

Library

Autonomous budget payments return success with output.value.redacted: true. Keep request_id, then call claimPaymentCredentials(request_id) to issue and receive the card once. If claim delivery is uncertain, do not create a replacement payment: the budget may already have been charged and the card cannot be recovered. The merchant is paid only when you use the card at checkout.

import { PayboxClient } from "@paybox-sh/sdk";

const paybox = PayboxClient.fromConfig();          // reads ~/.config/paybox + env
// or: new PayboxClient({ apiKey: "pbx_live_…", signingKey: "pbxk1.…" });

const { credentials, ungranted } = await paybox.listCredentials();
const pay = await paybox.requestPayment({
  credentialId: credentials[0].credential.id,
  merchant: "Acme",
  merchantUrl: "https://acme.com",
  amountCents: 1999,
});

// Ungranted credentials the user owns but hasn't granted this connector — pass
// an id to request_account_change's `add` to ask for access.
console.log(ungranted.map((c) => `${c.name} (${c.kind})`));

const sig = await paybox.requestWalletSign({
  credentialId: walletId,
  chain: "eip155:8453",
  intent: { op: "message", message: "gm" },
});                                                 // signs in-process if a key is set

// x402: discover a paid endpoint, then pay it — header mode (you replay the
// X-PAYMENT header) or gateway mode (paybox fetches the paid content for you).
const services = await paybox.discoverServices("weather api");
const rawServices = await paybox.discoverServices("weather api", { raw: true }); // debug only
const paid = await paybox.useService({ credentialId: walletId, url: services[0].resource });
// paid.response.output.value.response holds the resource's reply

const plugins = await paybox.discoverPlugins({ status: "enabled" });
const selected = plugins.plugins.find((plugin) => plugin.id === "aave");
const contract = await paybox.getPluginContract(selected!.contract_uri!);
const result = await paybox.usePlugin({
  pluginId: contract.contract.id,
  toolId: contract.contract.tools[0].id,
  input: {},
});

Run and resume a plugin request

runPlugin invokes a plugin once and drives its stored request. resumeRequest reads an existing request and does not invoke the plugin again. Signing follows validated Solana/EVM transaction capabilities and server-owned refresh_before_sign, not plugin names. resumeRequest also consumes stored wallet_sign transaction intents through the existing signer. Unknown formats, versioned plans and gasless prepared plans stop with outcome: "unsupported". Public plugins also use use_plugin, with their installation ID as plugin_id; request completion does not by itself prove a purchase or broadcast. Use the plugin contract to select an enabled tool and construct its input.

import type { UsePluginArgs } from "@paybox-sh/sdk";

async function runApprovedOperation(operation: UsePluginArgs) {
  const execution = await paybox.runPlugin(operation, { timeoutMs: 60_000 });
  if (execution.requestId) {
    await saveRequestId(execution.requestId);
  }
  return execution;
}

const execution = await paybox.resumeRequest(savedRequestId, {
  waitForApproval: true,
  timeoutMs: 60_000,
});

The example assumes application-owned storage through saveRequestId and savedRequestId. Keep the request ID so another process can resume after a pause. A paired signing key enables automatic signing. Set autoSign: false to stop before signing. The server still enforces wallet grants and approval requirements.

| Outcome | Meaning | | --- | --- | | terminal | Check response.status: success, denied, or error. A signature alone is not success. | | approval_required | The user must approve through Paybox. Approval waiting is disabled by default. | | signing_required | Automatic signing is disabled or a signing key is unavailable. | | unsupported | The result or signing plan is outside the supported contract. | | reconcile_required | The client cannot confirm completion. Query the same request before further action. | | deadline_exceeded / cancelled | The client stopped. The server operation can still finish. |

The default deadline is 300 seconds and includes network calls. Polling starts at 2 seconds, doubles when the status is unchanged, and stops increasing at 30 seconds. A status change resets the interval. intervalMs sets the starting interval from 1 to 30,000 milliseconds. signal accepts an AbortSignal for cancellation.

Do not start concurrent drivers for the same request. After an uncertain result, use getRequest before an explicit resume. The driver does not automatically retry a signature submission or create a replacement request. If invocation stops before a request ID arrives, reconcile outside this driver before invoking the plugin again.

usePlugin still returns the raw MCP result, including metadata. Use it for data tools and unsupported flows. The new methods do not change existing CLI commands. Funding requests stop with outcome: "unsupported", reason: "funding_required", and a non-signing pending_funding response. They never reopen or submit a plan.

Configuration

Resolution order: explicit constructor options → environment → stored config.

| Env | Meaning | |-----|---------| | PAYBOX_API_URL | API origin (default https://api.paybox.sh). | | PAYBOX_API_KEY | A pbx_live_* personal API key. | | PAYBOX_ACCESS_TOKEN | A raw OAuth access token. | | PAYBOX_SIGNING_KEY | A pbxk1. wallet signing key (enables sign/swap). | | PAYBOX_CONFIG_DIR | Override the config dir (default ~/.config/paybox). | | PAYBOX_NO_AUTO_UPDATE | 1 turns off the daily self-update of a global install. | | PAYBOX_UPDATE_REGISTRY | Registry the self-update checks and installs from (default https://registry.npmjs.org). Project .npmrc and npm_config_registry are ignored. |

paybox login writes ~/.config/paybox/config.json (mode 0600 on macOS/Linux). On Windows the POSIX mode bits don't restrict access — the file is not access-protected there, so prefer PAYBOX_API_KEY / PAYBOX_SIGNING_KEY env vars on shared Windows machines.

Headless and CI

Pairing needs a human to confirm the code, so CI cannot pair at run time. Pair once ahead of time as the identity CI will use, then carry both secrets:

# On a laptop. The pbx_live_ key comes from the PayBox app (Agents → create an
# agent, pick its wallets); it is shown once.
paybox login --key pbx_live_…      # authenticate as the client CI will use
paybox connect                     # pick the number; approve on any device
grep signingKey ~/.config/paybox/config.json
env:
  PAYBOX_API_KEY: ${{ secrets.PAYBOX_API_KEY }}          # pbx_live_…
  PAYBOX_SIGNING_KEY: ${{ secrets.PAYBOX_SIGNING_KEY }}  # pbxk1.…

PayboxClient.fromConfig() reads both from the environment, so the runner needs no config file, no browser, and no TTY.

Those two secrets are a matched pair: a signer is bound to the client that paired it. Present a pbxk1. to a different client — including the throwaway client that a plain paybox login registers — and signing fails with agent signer belongs to another client. It reads like a revocation but means you paired under a different identity. Rotating the API key mints a new client, so re-pair after rotation — paybox login drops the stored key when it does this and tells you to run paybox connect, rather than leaving one that cannot sign.

Develop

pnpm-lock.yaml also contains the ../mcp-app importer because this SDK consumes the iframe's signing core through file:../mcp-app. The iframe build shares this dependency resolution but keeps its installed modules separate.

pnpm install
pnpm typecheck
pnpm build           # tsup → dist/ (ESM + types + paybox bin)

# Refresh the generated tool types from the MCP tool contract:
pnpm gen

The argument types in src/types.generated.ts come from artifacts/contracts/mcp-tools-v1.json, the committed list of core MCP tools and their input schemas. CI fails when the tools change and the file does not, or when this file is not regenerated from it. Refresh it with PAYBOX_UPDATE_CONTRACTS=1 cargo test --lib mcp_tool_contract_matches_core_tools in server/. Response types in src/types.ts track server/src/models.rs.