Unified QRs for Bitcoin
No more on-chain and lightning UI tabs. No more wallet interoperability issues. A simple, backwards-compatible way to request bitcoin for on-chain and lightning.
The Problem
Asking users to choose between on-chain and lightning payments can be confusing — but it's been necessary to maintain interoperability between wallets.
Most wallets either take a lightning-only or on-chain-only approach. Wallets that support both use a tab or toggle for switching between the two formats.
What if we could simplify this so the user doesn't have to make these choices? And how might we do this in a way that maintains interoperability between wallets?
A Solution
BIP 321 Payment URIs with an optional lightning parameter
BIP 321 defines a URI scheme for creating a “payment link”. By default, it includes an on-chain address to send funds to.
BIP 321 was designed to be extensible. The spec allows for optional parameters in the URI. Why can’t one of these parameters be used to include a BOLT 11 invoice, or even a BOLT 12 offer in the future?
Examples
Note that every example features uppercase `bech32` strings (bitcoin addresses, invoices, and offers). When a QR code is encoded in mixed mode, it can use alphanumeric mode for the uppercase strings to reduce the resolution of the QR code and make it more easily readable by devices.
Unified QRs for Bitcoin
BIP 321 URI with BOLT 11 invoice (one-time use)

This includes an on-chain address and a BOLT 11 invoice. It is easily backwards compatible, but is quite large.
Raw Data
bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign%3A%20For%20lunch%20Tuesday&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6
BIP 321 URI with BOLT 12 offer (reusable)

Using an offer instead of an invoice reduces the QR code size significantly.
Raw Data
bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign%3A%20For%20lunch%20Tuesday&message=For%20lunch%20Tuesday&lno=LNO1PG257ENXV4EZQCNEYPE82UM50YNHXGRWDAJX283QFWDPL28QQMC78YMLVHMXCSYWDK5WRJNJ36JRYG488QWLRNZYJCZS
Standard QR Codes
BIP 321 URI with On-chain address (one-time use)

A standard BIP 321 URI, for reference. This has the smallest QR code, but will not work with lightning.
Raw Data
bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign%3A%20For%20lunch%20Tuesday&message=For%20lunch%20Tuesday
BOLT 11 Invoice
(one-time use)

BOLT 11 invoice QR codes are already significantly large, even without the additional data of the BIP 321 URI.
Raw Data
LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6
BOLT 12 Offer
(reusable)

A BOLT 12 offer on its own. Compact and reusable, but only works with lightning wallets that support BOLT 12.
Raw Data
LNO1PG257ENXV4EZQCNEYPE82UM50YNHXGRWDAJX283QFWDPL28QQMC78YMLVHMXCSYWDK5WRJNJ36JRYG488QWLRNZYJCZS
Why this technique?
BIP 321 is an existing and agreed-upon standard. Most existing on-chain bitcoin wallets already support BIP 321. When these wallets scan the QR code on the right, they will retrieve an on-chain address and ignore the Lightning invoice.
For Lightning wallets, adding support should be simple. They just need to know where to look for the Lightning invoice in the BIP 321 URI. Wallets can also give a choice of on-chain and Lightning, if the wallet supports both.
This technique is even mentioned in the BOLT 11 spec!

The Plan
Adoption of the a unified BIP 321 QR code for bitcoin is as simple as getting more Lightning wallets, exchanges, and other bitcoin services to support it. See below for the current list of support. You can help by testing your favorite wallets and services for support, or by implementing this BIP 321 support in a wallet or service that does not have support.
The most important next step is getting wallets and services to support scanning BIP 321 QR codes.
Once there is wide support for scanning in place, wallets projects can decide if they want to roll out support for generating BIP 321 QR codes. Likely, most projects will not default to generating BIP 321 QR codes if there is not wide support for scanning BIP 321 QR codes first.
How to contribute
How to test a wallet
Testing a wallet or service is easy. Choose a bitcoin app from the list below that has not been tested yet, or choose one that is not on the list. Then, open the app, scan the QR code below, and see what happens.

Interpreting what you see
- If the app is an on-chain only wallet:
- If the app fails to scan the QR code, then it can NOT scan BIP 321 QR codes. Lightning is not applicable in this case.
- If the app successfully scans the QR code and recognizes the "bc1q..." address, then it CAN scan BIP 321 QR codes. Lightning is not applicable in this case.
- If the app supports Lightning:
- If the app scans the QR code but tries to initiate an on-chain payment using the "bc1q..." address, then it CAN scan the BIP 321 QR code but can NOT recognize lightning.
- If the app scans the QR code and tries to initiate a Lightning payment, then it CAN scan the BIP 321 QR code and CAN recognize Lightning.
Optional: you may also document if the app is capable of creating a BIP 321 payment URI when you request a payment. The way to determine if a QR code is a BIP 321 URI is to decode the QR and see if it begins with
bitcoin:. If this is too advanced for you or you are otherwise unsure, you can simply say "I'm not sure" for this detail; this will most commonly be a no for most wallets today.
Once you have your results, submit a PR to update the wallet_support.json file on GitHub. If you are not comfortable working with the code, then simply file an issue in our GitHub repo.
How to implement support
Here's a list of references to help with implementation and testing.
- Bitcoin Payment Instructions Rust Crate from @TheBlueMatt
- QR Code Generator for Testing
- Test vectors from @prusnak
- Python script for generating test vectors from @prusnak
Software and services supporting BIP 321
Defining support
Hardware Support
BIP 321 QR codes that contain Lightning invoices can get very large. Here is documentation on how different mobile devices fare when attempting to scan these large QR codes.
These results differ from the results above. Here, we are simply checking if an app is capable of reading the very large QR code, and disregarding whether or not it notices the Lightning invoice.
Samsung Galaxy A12
- Scans the QR
Description
Works very good. It is capable of reading the QR from a surprising distance. If the QR takes up a quarter to a half the width of the screen, it will take a second to refocus and then scan. The closer the QR is to the camera, the faster it works.
Tested by@sbddesign
Common Questions & Concerns
QR code size is very large
The QR becomes large enough to cause scanning difficulties with some devices. This is a valid concern. In fact, BOLT 11 invoices alone also have scan-ability issues on some devices.
BOLT12 offers can significantly reduce the size of the QR code. Additionally, techniques like animated QR codes or NFC could help avoid scanning problems.
Does this take away choice from the user?
In many situations, the user already lacks a choice in the matter. For example:
- If the sending user has an on-chain-only wallet, then they have no choice: they can only pay on-chain.
- If the sending user has a Lightning-only wallet, then they have no choice: they can only pay via Lightning.
For wallets that support both on-chain and Lightning, it would be helpful to the user to default to the option that offers the lowest fees, which in most cases is going to be Lightning.
In edge cases where the on-chain fees are actually lower than Lightning, then the wallet could opt to send on-chain or even present the user which a choice: "You can save X amount on fees, but this transaction will take longer to confirm. Is this OK?"
Why not put a human-readable address inside a BIP 321 URI?
The QR you scanned should already contain everything needed to pay. A human-readable identifier e.g
bob@pay.medoesn’t — it’s a pointer that has to be resolved over the network before any payment can happen.
These identifiers are for names a human types or shares, not for a QR or link. Embedding one forces a DNS or LNURL lookup whose result the payer must trust on top of what they scanned: added latency, and another thing that can fail or be intercepted.
Used as intended — shared as a name a person types, not crammed into a scanned code — human-readable identifiers are a real UX win. To learn more, read Spiral’s Making Bitcoin Speak Human.