LNURL
A set of HTTP-based protocols extending Lightning with features like auth, pay, withdraw, and channel requests via simple URLs.
Key Takeaways
- LNURL is a family of HTTP-based protocols that wrap Lightning Network operations behind simple, scannable URLs: instead of generating a new Lightning invoice for every payment, a service can publish a single static QR code that handles the rest.
- The spec includes four core sub-protocols: LNURL-pay for receiving payments, LNURL-withdraw for pulling funds, LNURL-auth for passwordless login, and LNURL-channel for requesting inbound channels. Lightning Addresses are built directly on top of LNURL-pay.
- LNURL requires a web server and HTTPS, which contrasts with BOLT 12 offers: a fully decentralized alternative that uses onion messages instead of HTTP infrastructure.
What Is LNURL?
LNURL (Lightning Network URL) is a set of open protocols that make Lightning payments, withdrawals, and authentication accessible through standard HTTP requests. Rather than requiring users to manually copy and paste invoices or manage channel details, LNURL encodes a server URL into a scannable QR code. The wallet handles everything else automatically: fetching payment parameters, generating invoices, or signing authentication challenges.
The protocol was initially proposed in 2019 by Anton Kumaigorodski, with significant contributions from fiatjaf (later creator of the Nostr protocol). The original motivation was solving the inbound liquidity problem: enabling users to pay a service to open a Lightning channel to them. The spec quickly expanded to cover payments, withdrawals, and authentication, becoming one of the most widely adopted UX layers on top of Lightning.
The canonical specification lives at github.com/lnurl/luds and consists of 21 numbered documents called LUDs (LNURL Documents). Each LUD describes a modular piece of the protocol, and wallets can implement any subset while maintaining compatibility.
How It Works
Every LNURL interaction follows the same base pattern: encode a URL, let the wallet decode it, and exchange JSON over HTTPS.
Encoding
An LNURL is a cleartext HTTPS URL encoded using bech32: the same encoding scheme used for SegWit addresses. A URL like https://service.com/api?q=abc becomes a long bech32 string starting with lnurl1.... When rendered as a QR code, the string should be uppercase because QR alphanumeric mode is more compact for uppercase characters.
A later extension (LUD-17) introduced raw URL alternatives using scheme prefixes: lnurlp:// for pay, lnurlw:// for withdraw, lnurlc:// for channel, and keyauth:// for auth. These replace https:// and skip the bech32 step entirely.
Base Flow
- User scans a QR code or clicks a
lightning:LNURL...link - Wallet decodes bech32 to recover the cleartext URL
- Wallet makes an HTTP GET request to the URL
- Server returns a JSON object with a
tagfield identifying the protocol:payRequest,withdrawRequest,login, orchannelRequest - Wallet proceeds according to the rules for that tag
Errors at any step return a JSON object with {"status": "ERROR", "reason": "..."}. HTTPS with a valid certificate is mandatory for clearnet URLs. HTTP is acceptable only for Tor onion addresses. Endpoints must also set the CORS header Access-Control-Allow-Origin: * for browser wallet compatibility.
Core Sub-Protocols
LNURL-pay (LUD-06)
LNURL-pay allows a service to present a single static QR code for receiving payments with flexible amounts. The server specifies minimum and maximum amounts (in millisatoshis), and the wallet prompts the user to choose within that range.
// Step 1: Wallet GETs the LNURL endpoint
// Server responds:
{
"tag": "payRequest",
"callback": "https://service.com/pay/cb",
"minSendable": 1000, // 1 sat (in millisatoshis)
"maxSendable": 100000000, // 100,000 sats
"metadata": "[["text/plain","Pay to Service"]]"
}
// Step 2: User picks amount, wallet calls:
// GET https://service.com/pay/cb?amount=50000000
// Step 3: Server returns a BOLT-11 invoice:
{
"pr": "lnbc500u1p...",
"successAction": { "tag": "message", "message": "Thanks!" }
}Before paying, the wallet validates that the invoice's description hash matches sha256(metadata) and that the amount matches the user's selection. The successAction field lets the server return a message, URL, or AES-encrypted content (decryptable with the payment preimage) after payment completes.
LNURL-withdraw (LUD-03)
LNURL-withdraw reverses the flow: instead of the user paying, the service pays the user. This powers refunds, faucets, rewards, and withdrawal interfaces. The service publishes a QR code containing a withdrawal budget, and the user's wallet generates an invoice for the service to pay.
// Server responds to initial GET:
{
"tag": "withdrawRequest",
"callback": "https://service.com/withdraw/cb",
"k1": "random-hex-session-id",
"defaultDescription": "Withdrawal from Service",
"minWithdrawable": 10000,
"maxWithdrawable": 500000
}
// Wallet generates invoice, sends:
// GET <callback>?k1=<k1>&pr=<bolt11-invoice>
// Service pays the invoice asynchronouslyThe k1 parameter identifies the withdrawal session. Anyone with a valid k1 can initiate a withdrawal, so services should gate access behind authentication (such as LNURL-auth) before displaying withdrawal QR codes.
LNURL-auth (LUD-04)
LNURL-auth provides passwordless, privacy-preserving authentication using Lightning wallet keys. The service generates a random 32-byte challenge, and the wallet signs it with a domain-specific key pair derived from the wallet's seed.
- Service generates a random
k1challenge and embeds it in the LNURL - Wallet derives a domain-specific
linkingKeyusing a deterministic BIP-32 path - Wallet signs
k1with ECDSA on secp256k1 - Wallet sends signature and public key:
GET <callback>?sig=<hex>&key=<hex>&k1=<k1> - Service verifies the signature and logs the user in
The key derivation (LUD-05) uses hmacSha256(hashingKey, domain) to produce a unique key pair per domain. This means services cannot correlate users across domains, and the user's node key is never exposed. The service must also maintain a cache of unused k1 values and reject replayed challenges.
LNURL-channel (LUD-02)
LNURL-channel lets users request that a service open a Lightning channel to their node. The server provides its node URI, and the wallet connects and requests a channel. This was the original LNURL use case, addressing the inbound liquidity bootstrapping problem. It is the least widely adopted sub-protocol today, as Lightning Service Providers and automated channel management have largely replaced manual channel requests.
Lightning Addresses and LNURL
Lightning Addresses (LUD-16) are human-readable identifiers like user@domain.com that map directly to LNURL-pay. When a wallet encounters a Lightning Address, it converts it into a URL following a simple convention:
// Lightning Address: satoshi@service.com
// Wallet constructs:
GET https://service.com/.well-known/lnurlp/satoshi
// Server returns a standard LNURL-pay response:
{
"tag": "payRequest",
"callback": "https://service.com/pay/cb",
"minSendable": 1000,
"maxSendable": 100000000,
"metadata": "[["text/identifier","satoshi@service.com"]]"
}From there, the flow is identical to LNURL-pay. Lightning Addresses are essentially a human-readable wrapper around LNURL-pay that uses the .well-known URL convention. They inherit all of LNURL's server dependency and privacy characteristics: the domain owner must run a web server, and the sender's IP is exposed to that server.
LNURL vs. BOLT 12 Offers
BOLT 12 offers solve many of the same problems as LNURL but without HTTP infrastructure. Instead of web servers, BOLT 12 uses onion messages: encrypted, Lightning-native communication that requires only a Lightning node.
| Aspect | LNURL | BOLT 12 |
|---|---|---|
| Transport | HTTPS (web server required) | Onion messages (node only) |
| Infrastructure | Domain + TLS + web server | Lightning node |
| Privacy | Sender IP exposed to server | End-to-end encrypted |
| Recurring payments | Not natively supported | Built-in |
| Refund flow | Not built-in | Native via offer invoices |
| Adoption | Widely deployed | Growing, less mature |
LNURL is far more widely deployed today and works well for businesses that already run web infrastructure. BOLT 12 is the technically superior long-term approach for decentralized and privacy-focused use cases. The two protocols are likely to coexist: LNURL for services, BOLT 12 for peer-to-peer payments. For a deeper comparison, see BOLT 12 Offers Explained and Lightning Invoices: BOLT 11 vs. BOLT 12.
Use Cases
- Static payment pages: merchants display a single QR code that works for any amount, replacing the need to generate per-transaction invoices
- Tipping and donations: content creators, streamers, and open-source projects use Lightning Addresses or LNURL-pay QR codes for one-scan tipping
- Withdrawals and rewards: gaming platforms, cashback services, and faucets use LNURL-withdraw to let users pull funds instantly
- Passwordless login: services use LNURL-auth to authenticate users without passwords, emails, or third-party OAuth providers: the wallet is the identity
- NFC payments: projects like CoinCorner's Bolt Card embed LNURL-withdraw links in NFC cards, enabling tap-to-pay Lightning transactions at physical point-of-sale terminals
- Point-of-sale systems: BTCPay Server and LNbits integrate LNURL-pay to create reusable payment links for retail environments
Risks and Considerations
Server Dependency
Every LNURL interaction requires an HTTP request to a server. If the server goes down, all payment flows, withdrawals, and authentication fail. There is no fallback mechanism within the protocol. This creates a single point of failure that contrasts with Lightning's otherwise peer-to-peer architecture.
Privacy Exposure
The sender's IP address is disclosed to the LNURL server on every interaction, unless they use Tor. Servers can log payment requests, amounts, timing, and IP addresses. This undermines the privacy benefits of Lightning's onion routing, which normally hides the sender and receiver from intermediaries. For privacy-sensitive use cases, BOLT 12 offers or keysend payments avoid this exposure.
DNS and TLS Trust
LNURL depends on the domain name system and TLS certificate infrastructure. Domain names can be seized, censored, or revoked by registrars. A compromised server could return manipulated payment parameters: wrong amounts, wrong invoices, or attacker-controlled callback URLs. Wallet-side validation (checking description hashes and amounts) mitigates some of these risks, but users must still trust the domain they are interacting with.
Phishing Risk
Malicious QR codes could direct wallets to attacker-controlled servers that mimic legitimate services. Wallets should prominently display the domain name so users can verify they are paying the intended recipient. Unlike BOLT 12 offers, where the offer is cryptographically tied to a node identity, LNURL relies on DNS trust for authentication.
Fragmented Wallet Support
Not all wallets implement every LUD. A wallet might support LNURL-pay but not LNURL-auth, or handle successAction messages but not AES-encrypted content. This fragmentation can lead to inconsistent user experiences and requires services to test across multiple wallet implementations.
This glossary entry is for informational purposes only and does not constitute financial or investment advice. Always do your own research before using any protocol or technology.