StableInvoice

How it works

What StableInvoice is

A tool for building professional invoices and payment requests that settle in stablecoins, straight between wallets. There is no account, no custody and no database: an invoice lives inside its own link, and your client opens that link to pay from their own wallet.

Everything runs in your browser. Your keys never leave it, and neither does your invoice data — the payload rides in the part of the URL that browsers never send to a server.

Three kinds of link

Payment links get forwarded. Which kind you send decides what the recipient can trust.

Unsigned

The default. Fast, and works without a wallet connected.

  • Anyone holding the link can read it
  • Anyone forwarding it can change the recipient address
  • The payment page says exactly that, in plain words

Signed — recommended

One click. Binds the invoice to your Ethereum account.

  • Recipient address, amount, token, chain and expiry are all covered
  • Alter any of them and the payment page turns red and refuses to pay
  • Still readable by anyone holding the link

Encrypted

For invoices whose contents are nobody else’s business.

  • Only the holder of one X25519 key can read it
  • Signed as well, so tampering is still detected
  • Needs your client’s public key up front

What protects you

A correctly signed invoice can still be a fraudulent one. These cover that gap.

It remembers who you pay

The fraud that actually happens is not a stranger inventing a bill. It is a supplier you have paid eleven times, where the twelfth invoice quietly carries a different destination address. Everything else looks right because everything else is right — and no signature catches it, because the forged link is correctly signed by the forger.

So the payment page remembers which addresses you have paid each counterparty at. A familiar name with an unfamiliar address turns the page red and disables the pay button until you have checked. The record is written only after you actually pay — never just from opening a link, or a forged one would teach itself as trusted.

Safety numbers

“Confirm the address out of band” is useless advice when the address is 40 hexadecimal characters. In practice people check the first four and the last four — which is precisely the check a vanity-address generator beats.

So every recipient address also appears as a 20-digit safety number you can read down a phone line, in any language. The length is deliberate: a short fingerprint can be brute-forced until it collides.

What the app refuses to do

  • Substitute a different token when the one you chose is not on that chain
  • Build a link with an invalid or zero recipient address
  • Round an amount it cannot represent exactly
  • Show a green check for a sender it cannot genuinely confirm
  • Put your bank details into a shareable link

Test networks are kept apart

Sepolia and other test chains sit in their own group in every network picker, labelled not real money. An invoice issued on a testnet can never be paid, and in a flat list that reads like just another option.

How encrypted invoices work

Encryption runs in both directions of a relationship: your client generates a key and proves it is theirs, and then you encrypt to it.

If you are being invoiced

  1. Open Generate Key and create an X25519 keypair. It is made in your browser and never uploaded.
  2. Export it with a passphrase. The plain-text option exists, but a passphrase-wrapped file is useless to anyone who finds it.
  3. Press Sign Public Key to bind it to your Ethereum address, then Copy signed bundle.
  4. Send that bundle to whoever invoices you.

If you are sending the invoice

  1. Paste their bundle into the recipient key field, or check it on Verify Key.
  2. The app recovers the signature and confirms the key really belongs to that address, rather than trusting a bare key someone pasted.
  3. Build the invoice and choose Create Encrypted Pay Link.
  4. Only their private key opens it. Lose that key and the invoice is unrecoverable, by design.
An honest limit: a valid signature proves someone controls the address the link declares. It does not prove that address is your counterparty. Confirm a new sender through a channel other than the link itself, then mark them as confirmed so future links from them are recognised on this device.

Privacy and custody

  • No accounts, no sign-up, no invoice database
  • Payments go wallet to wallet; funds never pass through us
  • Private keys stay in your wallet, or are generated locally and never uploaded
  • Invoice data rides in the URL fragment, which browsers do not send to servers
  • Bank details stay in the PDF and are never embedded in a link
  • Sanctions screening shares only the recipient address with Chainalysis — never amounts, names, or the invoice itself

Under the hood

  • Vite multi-page build, Tailwind CSS, vanilla ES modules
  • jsPDF for export, fetched only when you generate a PDF
  • libsodium for X25519 encryption and Argon2id key wrapping
  • EIP-712 signatures; EIP-681 wallet deep links and QR codes
  • WalletConnect for mobile wallets; recipients screened against the OFAC SDN list before payment is enabled
  • All third-party code is self-hosted — nothing loads from a CDN
  • Strict Content Security Policy, with no inline scripts anywhere

From Telegram

Everything above assumes a browser. @StableInvoice_Bot does the common jobs from a chat, which is usually where the client already is.

Setting it up

  • /start — then /help for the full list
  • /setwallet 0x… — the address you get paid at, stored once
  • /setbillfrom and /setbillto — company and client details for invoice PDFs
  • /getwallet, /resetwallet — read it back, or delete it

Getting paid

  • /paymentlink charge 10 USDT on Polygon for 3 beers — plain English; the amount, token and network are read out of the sentence
  • /invoice — the same, plus a PDF
  • /payother — a transfer link for paying someone else
  • /verify <tx> <chain> and /checkpayment — confirm a payment landed

What it stores, and how

  • Your wallet address and billing details, so you do not retype them
  • Encrypted at rest with AES-256-GCM, bound to your Telegram id so one record cannot be replayed as another
  • Links are generated on demand — the bot keeps no invoice history
  • /resetwallet deletes the stored address

Two honest limits

  • Bot links are unsigned. They carry no signature, so a forwarded link can have its recipient address changed. For a stranger, make the link on the website and use Create Signed Link.
  • Encryption is browser-only. Encrypted links need a key that never leaves your device, so the bot cannot make them. It will tell you so rather than pretend.

Open @StableInvoice_Bot

Get in touch

Questions, bug reports, or something that looks wrong on a payment page — we would rather hear about it.

hello@bullproject.io

Or message @StableInvoice_Bot on Telegram.

StableInvoice is powered by Bull Project.