Build a Lightning Escrow with NWC Hold Invoices

Use Alby NWC SDK for conditional Lightning payments

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

  1. Escrow service generates preimage and payment_hash
  2. Escrow creates invoice using the payment_hash (keeps preimage secret)
  3. Payer pays invoice — sats are locked, not delivered
  4. When conditions are met, escrow calls settle_hold_invoice with the preimage — sats go to recipient
  5. 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.


No comments yet.