koerier
koerier is Dutch for courier: someone that collects and delivers messages. koerier collects
lightning invoice requests and delivers lightning invoices.
Usage
Install the Rust toolchain:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Clone this repository and install the binary:
git clone https://github.com/luisschwab/koerier
cd koerier
cargo install --path .
Create a TOML file with these fields:
[]
= "https://example.org" # the domain used on the callback URL
= "0.0.0.0:3441" # the address koerier will listen on
= "If you don't believe me or don't get it, I don't have time to try to convince you, sorry." # description that will be displayed when the LNURL endpoint is hit
= "./image.png" # optional: path to a PNG image that will be displayed when the LNURL endpoint is hit
[]
= "127.0.0.1:8080" # LND's REST address
= "/root/.lnd/tls.cert" # path to LND's TLS certificate
= "/root/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon" # path to LND's invoice macaroon
= 1 # the minimum allowed invoice amount in sats
= 1_000_000 # the maximum allowed invoice amount in sats
= 3600 # the invoice expiry time in seconds
Then run it:
koerier -c config.toml
[2025-09-06T02:49:15Z INFO koerier] Successfully parsed configuration from `config.toml`
[2025-09-06T02:49:15Z INFO koerier] koerier is bound and listening at 0.0.0.0:3441
Optionally, use the example systemd service provided here:
cp koerier.service.example /etc/systemd/system/koerier.service
systemctl daemon-reload
systemctl enable koerier.service
systemctl start koerier.service
Since koerier does not implement TLS termination, you need to have a webserver acting as a reverse proxy in front of it.
You can use the provided Caddyfile, or adapt it to another webserver implementation:
example.org {
handle /.well-known/lnurlp* {
reverse_proxy 10.10.10.10:3441 {
header_down Access-Control-Allow-Origin "*"
header_down Access-Control-Allow-Methods "GET, POST, OPTIONS"
header_down Access-Control-Allow-Headers "Content-Type"
}
}
handle /lnurlp/callback* {
reverse_proxy 10.10.10.10:3441 {
header_down Access-Control-Allow-Origin "*"
header_down Access-Control-Allow-Methods "GET, POST, OPTIONS"
header_down Access-Control-Allow-Headers "Content-Type"
}
}
}
Architecture
koerier is a middleware that implements the Lightning Address, specified in LUD06.
It sits between the caller, usually a lightning wallet, and an LND lightning node.
The caller hits the correct endpoint and receives a lightning invoice.
Lightning Address
A lightning address is an internet identifier identical to an email address–sats@luisschwab.net is a lightning address–designed to make it easy to pay to someone in a non-interactive way, without the need to ask the person for an invoice.
The part before the @ specifies the user and the part after the @ specifies the provider.
Let's say you want to make a payment to the sats user, which has an account with the luisschwab.net provider.
The caller can make a GET request to https://luisschwab.net/.well-known/lnurlp/sats, and receive a response
in this format:
Then the caller makes another GET request to the callback URL, with an amount parameter with the desired invoice
amount in milli-satoshis, respecting the boundaries set by minSendable and maxSendable (these are also in milli-satoshis):
curl "https://luisschwab.net/lnurlp/callback?amount=1000"
Then the caller extracts the pr field and pays the invoice normally.
[!NOTE] Currently, the username field is a catch-all: any username is valid. If you'd like the ability to define a set of valid usernames, open an issue and I'll address it.
Sequence Diagram
This is the sequence diagram for the entire workflow, in accordance with LUD06:
sequenceDiagram
actor Caller
participant koerier
participant LND
Caller->>koerier: GET '/.well-known/lnurlp/sats'
koerier-->>Caller: return callback '/lnurlp/callback' + parameters
Caller->>koerier: GET '/lnurlp/callback?amount=1000'
koerier->>LND: POST '/v1/invoices' + 1 sat parameter
LND-->>koerier: return 'Lightning Invoice (1 sat)'
koerier-->>Caller: return 'Lightning Invoice (1 sat)'
Caller-->>LND: Pay 'Lightning Invoice (1 sat)' over the LN