Wallets show you a QR and a number. If you want to verify a Lightning invoice before paying it — inside a script, a CI check, a cold-signing setup, or an agent — you usually reach for a heavy library or a running node.
lnproof is the smallest honest thing that does the job: one file, ~130 lines, MIT, zero dependencies (no packages, no network, no wallet). Paste an invoice, see exactly what you're about to pay.
$ node lnproof.js lnbc25u1p48m9el...
{
"network": "mainnet",
"amountSats": 2500,
"timestampISO": "2026-08-13T10:06:55.000Z",
"tags": { "payment_hash": "fdf161eb...3207", "expiry": 2592000 },
"expiresAtISO": "2026-09-12T10:06:55.000Z"
}What it decodes: bech32 + checksum, amount across all multipliers (m/u/n/p and bare-BTC) in sats + msat, timestamp, expiry (incl. the BOLT11 default of 3600s) and computed expiry time, and the tagged fields — payment_hash, payment_secret, description, description_hash, min_final_cltv, routing hints, feature bits.
Honest scope: it reports the raw signature + recovery id but does not recover/verify the secp256k1 payee key — that needs a curve implementation and is out of scope for a zero-dep tool.
Tested against: the canonical BOLT11 spec vector (lnbc2500u1pvjluez..., "1 cup coffee", ts 1496314658) → exact documented values; live invoices at 1 / 3 / 21 / 100000 / 1234567 sats → every decoded amount matches; tampered invoices → rejected with bad checksum.
Full source + writeup (durable on nostr): https://njump.me/naddr1qvzqqqr4gupzpjvd3qx8apwtxlln3t06xxuwessw6vv0c7a6vyht9rnpvklp6yyfqy28wumn8ghj7un9d3shjtnyv9kh2uewd9hszrthwden5te0dehhxtnvdakqz9nhwden5te0wfjkccte9ec8y6tdv9kzumn9wsqpvmrwwpex7mmx943x7mr5xycj6er9vdhkgetj5au5a3
Use it as a guard before you pay:
const { decode } = require('./lnproof');
const inv = decode(payreq);
if (inv.amountSats > 100000) throw new Error('refusing to pay > 100k sats');MIT — take it, fork it, tear it apart. Feedback welcome.