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

zro-payment

v0.2.2

Published

Branded ZRO payment QR code component

Readme

zro-payment

Accept payments on your website from any ZRO wallet.

Drop in a button. Your customer pays on the same device, or by scanning a QR code with the ZRO app on their phone. Settlement is onchain, instant and feeless.

Documentation · Get an API key

npm install zro-payment

Quick start

import { ZROPayButton } from 'zro-payment';

export default function Checkout() {
  return (
    <ZROPayButton
      apiKey="your_api_key"
      amount={24.99}
      returnUrl="https://yourstore.com/order/1234/thanks"
      onSuccess={(txHash) => showThankYou(txHash)}
    />
  );
}

Create an API key at zroapp.xyz/docs/keys. Each key is scoped to one Base, and payments settle into that Base's wallet.

[!IMPORTANT] onSuccess is a UI signal, not proof of payment. Confirm server-side before fulfilling an order — see Security.


How a payment works

  1. The customer clicks the button. The SDK creates a payment and receives a payment_id.
  2. The modal offers two ways to pay:
    • Pay on ZRO — opens the hosted checkout, where the customer confirms from their ZRO wallet. This is the path that works when they are already on their phone and cannot scan their own screen.
    • Scan the QR — for a customer at a desktop with the ZRO app on their phone.
  3. The SDK polls until the payment settles onchain, then calls onSuccess(txHash).

API

<ZROPayButton>

| Prop | Type | Default | Description | |---|---|---|---| | apiKey | string | — | Required. Key for the Base being paid. | | amount | number | — | Required. See Currency. | | currency | 'USDC' \| 'CADC' | 'USDC' | Token the amount is denominated in. | | returnUrl | string | — | Absolute http(s) URL to return the customer to after paying. | | onSuccess | (txHash: string) => void | — | Fires when the payment settles. UI only. | | apiUrl | string | ZRO API | Override for staging. | | walletUrl | string | https://zroapp.xyz | Hosted checkout origin. Override for staging. |

Appearance

| Prop | Type | Default | Description | |---|---|---|---| | label | string | 'Pay with ZRO' | Button text. | | accentColor | string | '#7C3AED' | Background colour of the trigger button. | | textColor | string | '#fff' | Text colour on the accent. | | radius | number \| string | 10 | Corner radius. 9999 for a pill, 0 for a square. | | className | string | — | Your own class. Turns off the built-in styles — see below. | | style | CSSProperties | — | Style overrides, merged last. |


Styling the button

Three levels, depending on how much control you want.

Theme it — keep the built-in layout, change the branding:

<ZROPayButton
  apiKey="your_api_key"
  amount={24.99}
  label="Buy now"
  accentColor="#ff5500"
  radius={9999}        // pill
/>

These props style the trigger button on your page. The modal's QR code and its Pay on ZRO button keep ZRO's own branding — once the customer is being handed to ZRO, those elements should look like ZRO.

Tweak it — merge individual CSS properties over the defaults:

<ZROPayButton apiKey="..." amount={24.99} style={{ padding: '14px 32px', fontSize: 16 }} />

Own it — pass a class and style it entirely yourself:

<ZROPayButton apiKey="..." amount={24.99} className="btn btn-primary" label="Checkout" />

[!NOTE] Passing className switches the built-in inline styles off. Inline styles beat CSS, so if they stayed on, your stylesheet would be silently overridden. With a class present, only your CSS and any explicit style prop apply.

For total control over the whole flow — your own modal, your own QR placement — use useZROPayment instead.


useZROPayment(options)

The same options, when you want to build the UI yourself.

const { isOpen, state, open, close, payUrl } = useZROPayment({
  apiKey: 'your_api_key',
  amount: 24.99,
});

| Returns | Description | |---|---| | state.status | 'idle' · 'loading' · 'ready' · 'completed' · 'error' | | state.qrPayload | Pass to <ZROQRCode> | | state.paymentId | Use this to confirm the payment from your server | | state.error | Human-readable message when status === 'error' | | payUrl | Hosted checkout link for the same-device path | | open() / close() | Control the flow |

<ZROQRCode>

<ZROQRCode payload={state.qrPayload} size={180} />

Renders the branded QR code the ZRO app scans.


Security

onSuccess is forgeable. It is a client-side callback: a customer can invoke it from the browser console, or stub the network request, and receive the goods without paying. Use it to show a receipt or advance the checkout step — then confirm the payment from your own server before releasing anything of value.

Treat apiKey as public. It ships in your site's JavaScript, so anyone can read it. It cannot redirect funds — the destination wallet is set server-side by the key's Base — but it can be used to create payments against your daily limit. Set an allowed domain on the key to limit where it can be used from.


Currency

amount is denominated in whatever you pass as currency, and no conversion is applied.

<ZROPayButton apiKey="..." amount={9.99} currency="CADC" />

Charging 9.99 as CADC means you receive 9.99 CADC, not 9.99 USDC. Price in the currency you are willing to accept, and reconcile the settled amount server-side before fulfilling.

amount must be finite, greater than zero, no more than 1,000,000, and have at most two decimal places.


Rate limits

Creating a payment counts against your key's daily limit. Status polling does not — you are billed for checkouts, not for how long a customer leaves the modal open.

The SDK polls every 2s for the first 30s, then every 10s, and stops after 5 minutes. It gives up immediately on 401, 403, 404 and 429 rather than retrying. A checkout expires 15 minutes after it is created if no transaction has been submitted for verification.


Requirements

React 17 or later. The package ships a "use client" banner, so it can be imported directly from a Next.js App Router server component.


Support

Questions and issues: [email protected]

License

MIT