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

paysovra

v1.0.1

Published

Official PaySovra SDK — accept crypto and stablecoin payments, non-custodially.

Readme

PaySovra SDK

Accept crypto and stablecoin payments, non-custodially. Funds settle straight to wallets you control — PaySovra never holds or routes them.

npm install paysovra

Requires a PaySovra account and a secret integration key. Node 18+.

Quick start

import { PaySovra } from "paysovra";

const paysovra = new PaySovra(process.env.PAYSOVRA_SECRET_KEY);

Server-side only. The secret key can create charges and read customer data, so it must never reach a browser.

Taking a payment from a web page

Authorise the amount on your server and hand the browser a token. The price never exists in client code, so a customer cannot edit it before paying.

// Your server
const { token } = await paysovra.checkout.createIntent({
  amountFiat: 49.99,
  currency: "EUR",
  orderId: "ORD-1234",
  metadata: { userId: "u_88" },   // comes back on the webhook
});
// The browser — the amount comes from the intent, not the page
window.PaySovra.open({ intentToken: token });

Verifying webhooks

This is the part worth using the SDK for. constructEvent does a timing-safe comparison and rejects deliveries outside a five-minute window, so replays and forged signatures fail before your code sees them. It throws rather than returning unverified data.

import { webhooks, SignatureVerificationError } from "paysovra";

app.post("/webhooks/paysovra",
  express.raw({ type: "application/json" }),   // RAW body, not parsed
  (req, res) => {
    let event;
    try {
      event = webhooks.constructEvent(req.body, req.headers, process.env.PAYSOVRA_WEBHOOK_SECRET);
    } catch (err) {
      if (err instanceof SignatureVerificationError) return res.status(400).send(err.message);
      throw err;
    }

    if (event.event === "payment.confirmed") {
      fulfillOrder(event.orderId);
    }
    res.json({ received: true });
  });

The body must be the exact bytes received. A body that has been parsed and re-stringified will not verify — key order and whitespace change the hash.

Payments

const payment = await paysovra.payments.create({
  amountFiat: 49.99,
  currency: "USD",
  cryptoAsset: "USDC_BASE",
  orderId: "ORD-1234",
});

await paysovra.payments.get(payment.id);
const { data, total } = await paysovra.payments.list({ page: 1, limit: 50 });

Products, invoices, customers

await paysovra.products.create({
  name: "Pro licence",
  type: "digital",
  price: 129,
  currency: "GBP",
  deliveryConfig: { linkUrl: "https://example.com/download" },
});

const { invoice } = await paysovra.invoices.create({
  items: [{ name: "Consulting", quantity: 4, unitPrice: 250 }],
  currency: "EUR",
  customerEmail: "[email protected]",
});
await paysovra.invoices.send(invoice.id);

await paysovra.customers.list({ limit: 100 });

products.update and invoices.update replace the record — send the full definition, not a patch. Fetch first if you mean to change one field.

Types

Assets and currencies are literal unions, so a typo is a compile error rather than a runtime 400.

import type { CryptoAsset, Currency, Payment, WebhookEvent } from "paysovra";

Assets: BTC LTC ETH TRX SOL POL BNB, plus USDC/USDT on Ethereum, Polygon, BNB Chain, Arbitrum, Optimism, Base, Solana and TRON.

Currencies: USD EUR GBP CAD AUD PLN INR. The exchange rate is locked when the customer commits, so what arrives matches what you charged.

Errors

import { PaySovraAPIError } from "paysovra";

try {
  await paysovra.payments.create({ /* … */ });
} catch (err) {
  if (err instanceof PaySovraAPIError) {
    err.status;         // HTTP status
    err.isAuthError;    // 401/403 — wrong key, or publishable where secret is needed
    err.isRateLimited;  // 429
    err.issues;         // field-level validation detail when supplied
  }
}

Requests carry an idempotency key automatically and retry on 429 and 5xx, so a network blip cannot create a duplicate payment.

Testing

Point at a testnet instance and integrate end to end without spending real money. Sepolia, Polygon Amoy, Base/Arbitrum/Optimism Sepolia, Solana Devnet and TRON Nile are supported, with test USDT and USDC contracts on Sepolia.

new PaySovra({ apiKey: "sk_test_…", baseUrl: "https://your-test-instance" });

Links

License

MIT