The accepting side of private payments on Starknet. STRK20 gives wallets a way to send money privately; this gives applications a way to get paid that way: an embeddable widget, per-invoice addresses, receipts, and a headless watcher that confirms payments over public RPC with no proving service in the loop.
A coin-op arcade that sells credits through the widget. Runs on a mock wallet, so the whole flow works with nothing installed.
NO WALLET NEEDEDCreate a shareable payment link, or open one and pay it with a real wallet on Starknet mainnet.
MAINNET · NEEDS READY XCreate invoices, watch them settle, export the ledger. Talks to the watcher, the bundled confirmation server, and falls back to sample rows when it cannot reach one.
NEEDS THE WATCHERNot on npm yet: publishing is pending. Until then, clone the
repo and npm install ./packages/strk20-pay.
import { mountCheckout, WalletApiAdapter } from "strk20-pay";
mountCheckout(document.getElementById("checkout")!, {
invoice: {
id: "order_1042",
token: "STRK",
amount: "25",
mode: "address",
receiveAddress: "0x…", // fresh, one per invoice
network: "mainnet",
createdAt: Date.now(),
},
wallet: new WalletApiAdapter({ network: "mainnet", rpcUrl: "https://rpc.starknet.lava.build" }),
// Must resolve to a BOOLEAN meaning "the money arrived". `r.ok` is only
// "the server answered", and an unpaid invoice answers 200 too.
confirm: (invoice) => fetch(`/api/paid/${invoice.id}`).then((r) => r.json()).then((b) => b.paid === true),
onPaid: (receipt) => console.log(receipt),
});
underpaid rather than expired, late ones become paid_late
instead of being dropped, and an address is never released for reuse once anything has landed
on it.timestamp.body, one delivery id per event to dedupe on, a retry queue persisted with
the ledger, and a redelivery endpoint.