BIP-21 — bitcoin: payment-request URIs (summary)¶
A condensed reference for the part of BIP-21 cuere implements in
bitcoin_uri. It is a summary, not the spec — read
the original for anything load-bearing.
Grammar¶
bitcoinurn = "bitcoin:" bitcoinaddress [ "?" bitcoinparams ]
bitcoinaddress = *base58 | bech32 ; the on-chain address
bitcoinparams = bitcoinparam [ "&" bitcoinparams ]
bitcoinparam = amountparam | labelparam | messageparam | otherparam
amountparam = "amount=" *digit [ "." *digit ]
labelparam = "label=" *pchar ; percent-encoded
messageparam = "message=" *pchar ; percent-encoded
amountis denominated in BTC (decimal), not satoshis — e.g.amount=20.3is 20.3 BTC. It is a plain decimal: no scientific notation, no thousands separators. One satoshi =0.00000001BTC, so the value is meaningful to at most 8 fractional digits.label/messageare free-form human text and MUST be percent-encoded (RFC 3986).labelnames the payee/address;messageis a note shown to the user.- Keys are case-sensitive. Unknown
req-*parameters a wallet does not understand must cause it to reject the URI; other unknown parameters are ignored.
What cuere does¶
bitcoin_uri(address, *, amount=None, label=None, message=None):
- Validates
addressstructurally against the base58 + bech32 alphabet ([0-9A-Za-z]+). This is not a base58check / bech32 checksum verification — that would need the checksum algorithms cuere intentionally does not bundle. - Renders
amount(acceptsDecimal/int/str, neverfloat— binary floats cannot represent decimal money exactly) as a plain BTC decimal, and rejects non-finite, non-positive, or finer-than-one-satoshi (>8 fractional digit) values. - Percent-encodes
label/messagewithquote(safe="")(so spaces become%20, not+). ANoneparameter is omitted; an explicit empty string is kept as a present-but-empty value. - Emits parameters in a fixed
amount→label→messageorder for reproducible output.
Out of scope: req-* parameters, BIP-72 r= payment-protocol URLs, and any
checksum validation.
Why optimize_uri only touches bech32, lowercase, no-query URIs¶
A QR code is smallest when its payload fits alphanumeric mode (digits,
upper-case A–Z and a few symbols). A bech32 address (BIP-173) is
case-insensitive, so a fully lowercase bitcoin:bc1… URI with no query
string can be uppercased wholesale to reach alphanumeric mode and shrink the
code — losslessly. optimize_uri does exactly this
and only this:
- only the
bitcoin:/lightning:schemes (known case-insensitive); - only when the URI is already entirely lowercase (so uppercasing cannot destroy significant case);
- only when the uppercased form is fully QR-alphanumeric (a
?amount=…query contains?/&/=, which are not alphanumeric, so any URI with parameters is returned unchanged).
It is deliberately not applied to case-significant schemes such as
ethereum: (EIP-55 checksums) — see eip-681.md.