BIP-21, the format every wallet understands
A Bitcoin payment QR code encodes a BIP-21 URI — a scheme agreed across the Bitcoin ecosystem so that any wallet can read a payment request from any source:
bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?amount=0.00125&label=Kiosk%203
The address is mandatory; everything after the ? is optional:
| Parameter | Purpose | Notes |
|---|---|---|
amount |
Requested amount in BTC | Decimal, not satoshis. 0.001, never 100000 |
label |
Name of the recipient | Shown in the wallet, saved to history |
message |
What the payment is for | Shown at confirmation |
The amount unit trips people up regularly. BIP-21 specifies BTC, so a request for 100,000 satoshis is amount=0.001. Writing amount=100000 requests one hundred thousand bitcoin, which the wallet will happily display and the user will hopefully notice.
The uppercase trick that halves your code
This is the one genuinely non-obvious optimisation in Bitcoin QR codes, and it matters because address strings are long.
QR encoding has an alphanumeric mode that packs two characters into 11 bits, against 8 bits per character in byte mode — roughly 31% more efficient. It covers digits, uppercase A–Z, space, and $ % * + - . / :. Lowercase letters are excluded.
Bech32 addresses — the ones starting bc1 — are case-insensitive by design, precisely so they can be uppercased for this purpose. The BIP-173 specification recommends exactly this. So:
bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq → byte mode
BITCOIN:BC1QAR0SRRR7XFKVY5L643LYDNW9RE59GTZZWF5MDQ → alphanumeric mode
The second produces a visibly coarser, more robust code from the same data. The scheme name BITCOIN: is case-insensitive per the URI spec, and the bech32 checksum validates identically in either case.
Two important limits:
- This only works for bech32 (
bc1…) addresses. Legacy addresses starting1or3use Base58Check, which is case-sensitive — uppercasing one produces a different, invalid address. Never do it. - Query parameters break it. Adding
?amount=0.001introduces?and=, which are not in the alphanumeric set. Good encoders segment the payload so the address portion still benefits, but the saving shrinks.
Address types and what they cost you
| Type | Prefix | Length | Notes |
|---|---|---|---|
| Legacy (P2PKH) | 1 |
26–34 | Case-sensitive, highest transaction fees |
| Script (P2SH) | 3 |
34 | Case-sensitive |
| SegWit (P2WPKH) | bc1q |
42 | Case-insensitive, lower fees |
| Taproot (P2TR) | bc1p |
62 | Case-insensitive, longest string |
Taproot addresses are half again as long as SegWit ones, which shows up directly as a denser code. Uppercasing recovers most of that difference.
Verify before you print, and verify again
A Bitcoin transaction is irreversible. There is no chargeback, no dispute process, and no support line. A wrong address in a printed QR code means every payment made through it is gone permanently.
This changes what "testing" means. Before any code goes to print or onto a website:
- Scan your own code with the wallet you actually use and confirm the address it shows matches, character for character, the one you intended. Check the first six and last six characters at minimum; ideally the whole string.
- Send a small test amount and confirm it arrives. This is the only test that proves the whole chain works.
- Check the amount field if you set one — decimal point in the right place, correct number of zeros.
- Re-verify after any design work. A designer regenerating the code from a re-typed address is a realistic way to introduce a single-character error.
Bech32 has a built-in checksum that catches most typos, and wallets will refuse an address that fails it. That is a real safety net but not a complete one, and Base58 legacy addresses have weaker protection.
Address reuse is a privacy problem
A printed QR code necessarily reuses one address for every payment. The Bitcoin blockchain is public, so anyone who scans your code can look up that address and see:
- Every payment ever made to it, with amounts and timestamps
- The total balance held
- Onward transactions, and often the addresses those went to
For a business, this means a customer can see your takings. For an individual accepting donations, it means anyone can see exactly how much you have received. Standard practice in wallet software is to generate a fresh address per transaction specifically to avoid this.
If you need a static printed code and care about privacy, the practical options are:
- A payment processor or point-of-sale system that generates a fresh address per transaction and displays it on a screen
- A BIP-21 URI pointing at a payment page rather than a raw address, so a new address is issued per visitor
- Accepting the exposure as a deliberate trade-off for a donation address, which many projects reasonably do
There is no way to have a static printed address and rotating addresses at the same time. Choose knowingly.
Amount, price volatility, and printed material
If you set an amount, remember it is denominated in BTC and the fiat value of that amount changes continuously. A code printed with amount=0.0004 for a £25 item is correct on the day it is printed and wrong within a week.
For fixed-price goods, either omit the amount and let the customer enter it, or use a payment processor that quotes in fiat and converts at the moment of payment. Static amounts belong on codes with a short life — a specific invoice, a one-off request — not on a menu or a price list.
Where these are used
- Donation pages and printed appeals, where address reuse is an accepted trade-off
- Invoices with a specific amount and a short validity window
- Point-of-sale displays driven by software that generates a fresh code per transaction
- Conference and meetup tip jars
- Person-to-person transfers, where showing a code on one screen and scanning it with another eliminates the risk of transcribing a 42-character address by hand
That last one is the most underrated use. Manually copying a Bitcoin address between two devices is exactly the kind of task humans do badly and irreversibly.
Frequently asked questions
Should I uppercase my Bitcoin address?
Only if it is a bech32 address starting bc1. Those are case-insensitive by design and uppercasing lets the encoder use alphanumeric mode, producing a significantly coarser and more scannable code. Never uppercase a legacy address starting 1 or 3 — Base58 is case-sensitive and you will create an invalid address.
Is the amount in BTC or satoshis?
BTC, per the BIP-21 specification. 100,000 satoshis is amount=0.001. Writing the satoshi figure directly would request one hundred thousand bitcoin.
Can anyone see how much I have received?
Yes. The blockchain is public, so any scanner can look up the address and see its complete transaction history and balance. This is inherent to reusing a single printed address and is the main argument for a payment processor that issues a fresh address per transaction.
What happens if the address is wrong?
Funds sent to a wrong but valid address are unrecoverable — there is no reversal mechanism. Bech32's checksum causes wallets to reject most mistyped addresses outright, but this is a safety net, not a guarantee. Always send a small test payment before publishing a code.
Do all wallets support this format?
BIP-21 is the de facto standard and every mainstream wallet reads it. Support for the optional label and message parameters varies — some wallets display them, some ignore them — but the address and amount are handled universally.
Should I put a fixed amount on printed material?
Generally no. The BTC amount is fixed but its fiat value is not, so a printed price drifts within days. Use amounts only on short-lived codes such as a specific invoice, or use a processor that quotes in fiat and converts at payment time.
Is my wallet address sent to your servers?
No. The BIP-21 URI is assembled and the image rendered entirely in your browser. Nothing you enter is transmitted to us or stored anywhere.