Integration Guide

Accept BB84 Payments On Your Site

Drop a QR code onto a checkout page, invoice, or donation button that already carries the amount and currency — no backend, no wallet connection, no API key. The customer scans it with the BB84 app, and the recipient, amount, and asset (USDC or EURC) are filled in automatically.

It is the same payload shape the BB84 app’s Receive screen generates — bb84-pay.js just makes it embeddable on your page.

Quick Start

Add this to any page. Replace shop.bb84.eth with your own address or bb84.eth name.

<!-- 1. A placeholder where the QR should appear -->
<div data-bb84-pay
     data-to="shop.bb84.eth"
     data-amount="20"
     data-asset="usdc"></div>

<!-- 2. The widget script — finds it and renders the code -->
<script src="https://bb84.com/bb84-pay.js" defer></script>
✅
That's it. bb84-pay.js scans the page for data-bb84-pay elements on load, lazy-loads the (tiny) QR-rendering library from cdnjs the first time it's needed, and draws a self-contained QR + amount caption in place.

The Payload

A BB84 payment-request QR encodes an ethereum: URI — the recipient, followed by the amount in the asset's smallest unit:

ethereum:<recipient>?value=<raw-units>&asset=<usdc|eurc>

<recipient> is a 0x… address, a *.bb84.eth name, or a real Mainnet *.eth name. Two concrete examples:

// Request 20 USDC
ethereum:shop.bb84.eth?value=20000000&asset=usdc

// Request 9.50 EURC
ethereum:shop.bb84.eth?value=9500000&asset=eurc

You never need to hand-build this string — BB84Pay.buildValue(to, amount, asset) does the decimal-to-raw-units conversion for you (see Programmatic API).

Amount & Asset

value is always an integer in the asset's smallest unit, matching how BB84 stores balances on-chain:

Assetdata-assetDecimals"1" means
Circle USDCusdc60.000001 USDC
Circle EURCeurc60.000001 EURC
⚠️
Leaving out data-amount renders an address-only QR (a generic "pay me" code, no fixed amount) — the customer types their own amount in the app. This is intentional: it's how the widget stays useful for tip jars and donation pages, not just fixed-price checkouts.

What Happens on Scan

1

Customer opens the BB84 app and taps the QR icon on Send

The camera reads the ethereum: URI straight off your page — no app switch, no copy-pasting an address.

2

Recipient, amount, and currency are filled in automatically

If the code specifies asset=usdc, the app switches its active currency to USDC so the right balance and OTA are shown — since this is an explicit request from you, not something the customer typed themselves.

3

Customer reviews and sends

Nothing leaves their device until they confirm — the widget only ever displays a request, it can't move funds on its own.

Under the hood this is the exact same shorthand the BB84 app also accepts when typed directly into the recipient field, e.g. 20usd.shop.bb84.eth — handy for sharing a request over chat instead of a QR image.

Declarative Embed

The simplest integration needs no JavaScript of your own. Add one <div data-bb84-pay> per QR code you want on the page:

<div
  data-bb84-pay
  data-to="shop.bb84.eth"       <!-- required -->
  data-amount="49.90"       <!-- optional -->
  data-asset="eurc"         <!-- "usdc" | "eurc", required with data-amount -->
  data-size="220"           <!-- optional, pixels, default 200 -->
  data-label="true"          <!-- optional, shows "Requesting 49.90 EURC" -->
></div>

Elements are matched once on DOMContentLoaded. Adding a widget div later (e.g. after fetching a cart total) — call BB84Pay.init() to pick up any new ones, or just call BB84Pay.render() directly.

Programmatic API

For a checkout flow where the total isn't known until runtime:

BB84Pay.render("#checkout-qr", {
  to:     "shop.bb84.eth",
  amount: cartTotal.toFixed(2),   // decimal string, e.g. "49.90"
  asset:  "usdc",               // "usdc" | "eurc" — required with amount
  size:   220,
});

BB84Pay.render(target, options)

Draws the QR into target (a CSS selector string or a DOM element). Returns a Promise that resolves once drawn, and rejects with a descriptive error if to/amount don't parse — the widget also shows that error inline so a bad integration fails loudly, not silently.

OptionTypeDefaultNotes
tostring—Required. Address, bb84.eth, or Mainnet .eth name.
amountstring | numbernoneOmit for an address-only, any-amount QR.
asset"usdc"|"eurc"noneRequired when amount is set. ETH is no longer supported — the widget shows an error instead of a QR.
sizenumber (px)200Outer widget width/height.
labelbooleantrue when amount setShows a "Requesting X ASSET" caption under the code.

BB84Pay.buildValue(to, amount, asset)

Returns the raw ethereum:… string without rendering anything — useful if you're feeding your own QR library (a native app, a PDF invoice generator, etc.) instead of the DOM widget. Returns null if the inputs don't parse.

const value = BB84Pay.buildValue("shop.bb84.eth", "20", "usdc");
// "ethereum:shop.bb84.eth?value=20000000&asset=usdc"

Live Demo

This calls the real bb84-pay.js hosted at /bb84-pay.js — the exact widget your page would load.

No-JS Alternative

If your site can't load third-party scripts at all, generate the QR once ahead of time in the BB84 app’s Receive screen, save the image, and embed the image directly — a static <img> tag works everywhere. For a dynamically-computed amount, build the ethereum:… string yourself using the format in The Payload and feed it to any QR-code image generator.

Security Notes

  • The widget only displays a request — it never has access to funds, private keys, or the customer's device beyond rendering a QR image.
  • bb84-pay.js is static and unauthenticated by design, same as any QR-image generator — nothing about it needs an API key, and nothing you embed can be revoked or rate-limited server-side.
  • Double-check data-to is your own address or bb84.eth name before shipping — the widget validates the shape of the recipient (a valid address or ENS name) but has no way to know whose it is.
  • The QR-rendering library (qrcodejs) is lazy-loaded from cdnjs.cloudflare.com only once, and only if window.QRCode isn't already present — check your CSP allows that origin if you enforce one.

Support Ticket

Frage, Bug-Report oder Feedback — wir melden uns per E-Mail.

Impressum·Privacy·Terms