BOLT 12 vs BOLT 11: what changed and why it matters
Bitcoin’s Lightning Network originally used BOLT 11 for invoices — the familiar lnbc… strings you see in most Lightning wallets. BOLT 11 works well for single payments: a merchant generates an invoice, the customer pays it, done. But BOLT 11 has significant limitations that become apparent at scale.
A BOLT 11 invoice is single-use. Every payment requires a fresh invoice from the payee. This makes static donation links impossible — if you publish a BOLT 11 invoice and 100 people try to pay it, only the first succeeds. Every subsequent payer needs to fetch a new invoice before paying, which requires the recipient to be online.
BOLT 11 leaks the recipient’s node. The invoice encodes the node public key of the final recipient. Anyone holding the invoice can identify the destination node on the Lightning Network graph, enabling both surveillance and denial-of-service attacks.
BOLT 12 solves both problems through a combination of reusable offers and onion messages.
Reusable offers
A BOLT 12 offer (HRP: lno) is a static, reusable invitation to pay. When a payer wants to pay an offer, they send an invoice request (HRP: lnr) to the offer issuer through the Lightning Network using onion messages. The issuer responds with a fresh invoice (HRP: lni) tailored to that specific payer. The actual payment then proceeds normally.
This flow allows:
- Static donation strings. You publish one offer string. It works for every payer, indefinitely.
- Subscriptions. The payer can re-request invoices on a schedule, paying the same offer repeatedly.
- Refunds. BOLT 12 offers can include a refund offer, enabling structured payment reversals.
- Currency flexibility. Offers can specify an amount in a non-Bitcoin currency with conversion applied at invoice time.
Onion messages
BOLT 12 relies on onion messages — a mechanism for routing arbitrary messages through the Lightning Network using the same onion routing as payments, but without locking up any funds. This enables the offer → invoice-request → invoice handshake without requiring the payee to maintain a direct TCP connection.
Onion messages also preserve recipient privacy. The offer string can contain blinded paths — a pre-encrypted route hint that allows the payer to reach the recipient without ever knowing the recipient’s node identity. The recipient’s public key is hidden inside the onion.
The three HRP types
Every BOLT 12 message is bech32m-encoded with a specific Human-Readable Part (HRP) that identifies the message type:
-
lno1…— Offer. A static, reusable invitation to pay. This is what you publish publicly. It contains: what amount to pay (or a variable-amount placeholder), a description, optional currency and conversion rate, and optionally blinded paths to the recipient. -
lnr1…— Invoice Request. A message from payer to payee, sent in response to an offer. It contains: the offer ID being responded to, the payer’s public key (for the reply path), and optionally a payer note or proof of payment. -
lni1…— Invoice. A single-use invoice generated in response to an invoice-request. Contains: amount in millisatoshis, payment hash, expiry time, routing hints (possibly blinded), and signature.
Note that lni BOLT 12 invoices are different from BOLT 11 invoices (lnbc…) — they are not interchangeable and require a BOLT 12-capable wallet to pay.
bech32m vs bech32
BOLT 11 uses bech32 (the original Segregated Witness encoding). BOLT 12 uses bech32m, a slightly modified version that improves error detection for longer strings. The checksum polynomial differs, which means bech32 and bech32m strings are not interchangeable, and a bech32 decoder will correctly reject a BOLT 12 offer as invalid.
This decoder uses the bech32m variant to validate and decode BOLT 12 strings.
Wallet support status
BOLT 12 is a relatively young specification that required significant protocol additions (onion messages, blinded paths). As of 2026, support is growing:
- Core Lightning (CLN): First full implementation. Offers have been production-ready since CLN 22.11. BOLT 12 is the native payment protocol for CLN.
- Phoenix Wallet: Added BOLT 12 offer support in 2024. One of the most user-accessible BOLT 12 implementations.
- LDK (Lightning Development Kit): Active BOLT 12 implementation. Powers several wallets that are rolling out support.
- LNbits: Added BOLT 12 offer generation as an extension.
- LND: Onion message support and BOLT 12 are in active development as of 2026 — not yet fully production-ready.
- Eclair / Phoenix (server): BOLT 12 support via Eclair’s implementation.
The ecosystem is moving quickly. Checking each wallet’s current release notes is the most reliable way to confirm support.
Privacy and donation flows
BOLT 12 is a significant privacy improvement over BOLT 11 for donations and recurring payments:
- You publish one offer, not one invoice per payment. Nobody can infer how many times you’ve been paid just from the static offer string.
- Blinded paths hide your node. If you include a blinded path in your offer, payers cannot identify your node on the network graph.
- No payment hash is reused. Each invoice generated from the same offer has a unique payment hash, preventing the correlations that would arise from a naively reused BOLT 11 invoice.
For a Bitcoin developer accepting donations, a BOLT 12 offer with a blinded path is considerably more private than a static BOLT 11 invoice — and more functional, since it works for every payer without requiring any server-side action per payment.
Current decoder scope
This decoder validates the bech32m encoding and identifies the HRP type. It displays the raw payload as hex for inspection. Full TLV (Type-Length-Value) stream parsing — which would extract the amount, description, issuer name, blinded paths, and other structured fields from the payload — is in progress. The TLV format used by BOLT 12 is defined in the BOLT 12 specification and requires careful incremental parsing; that work will appear in a future update of this tool.
In the meantime, the envelope view tells you: whether the string is well-formed bech32m, which BOLT 12 message type it represents, and how many bytes of payload it carries.