Build a Lightning Escrow with NWC Hold Invoices
Build a Lightning Escrow with NWC Hold Invoices
Normal Lightning invoices are atomic: you pay, the recipient gets the sats, done. There’s no way to say “hold this payment until the work is delivered” or “refund if the buyer disputes.”
Hold invoices fix this. The payer locks sats into the invoice, but the recipient doesn’t receive them until they reveal a secret (the preimage). If something goes wrong, the invoice is canceled and the payer’s sats return automatically.
Alby Hub now supports hold invoices via NWC. Here’s how to use them.
How Hold Invoices Work
- Escrow service generates preimage and payment_hash
- Escrow creates invoice using the payment_hash (keeps preimage secret)
- Payer pays invoice — sats are locked, not delivered
- When conditions are met, escrow calls
settle_hold_invoicewith the preimage — sats go to recipient - If conditions fail, escrow calls
cancel_hold_invoice— sats return to payer
The entity that creates the preimage controls whether the payment settles or cancels.
Generate Preimage and Payment Hash
import crypto from "crypto";
function generateHoldInvoiceKeys() {
const preimageBytes = crypto.randomBytes(32);
const preimage = preimageBytes.toString("hex");
const paymentHash = crypto
.createHash("sha256")
.update(preimageBytes)
.digest("hex");
return { preimage, paymentHash };
}
Create the Hold Invoice
import { nwc } from "@getalby/sdk";
const client = new nwc.NWCClient({
nostrWalletConnectUrl: process.env.NWC_URL,
});
const holdInvoice = await client.makeHoldInvoice({
amount: 50000 * 1000,
payment_hash: paymentHash,
description: "Escrow: Logo design job #42",
expiry: 3600,
});
Settle or Cancel
// Release funds
await client.settleHoldInvoice({ preimage });
// Or refund payer
await client.cancelHoldInvoice({ payment_hash: paymentHash });
Use Cases
- Freelance marketplaces — lock payment, release on delivery
- Bug bounties — lock bounty when PR submitted, release on merge
- P2P trades — atomic escrow for peer-to-peer exchange
- E-commerce — hold payment until shipping confirmation
Full tutorial with Express escrow server: https://maximumsats.com/blog/nwc-hold-invoices-escrow
Resources: @getalby/sdk, NIP-47, Alby Hub. Hold invoices turn Lightning into a programmable escrow layer.