April 28, 2026

Accept Lightning Payments in Node.js — 5 Minute Guide

Step-by-step tutorial to accept Bitcoin Lightning payments in your Node.js app using the LN Merchant API. Create invoices, display QR codes, and detect settlements.

Bitcoin Lightning payments settle in seconds and cost under a penny. Here’s how to accept them in your Node.js app.

What you’ll build

A simple payment flow: your app creates a Lightning invoice, the customer scans a QR code, and you get notified when they pay. Total integration time: about 5 minutes.

Prerequisites

Step 1: Create a payment

One POST request creates a Lightning invoice. You can specify the amount in USD — we handle the BTC conversion at the current spot rate.

const response = await fetch('https://api.lnmerchant.com/payments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    currency: 'BTC',
    amountCents: 2500,  // $25.00 — auto-converted to sats
    description: 'Premium membership',
  }),
});

const payment = await response.json();
// payment.invoice = "lnbc..." (BOLT-11 invoice string)
// payment.amountSats = 26315
// payment.id = "abc-123"

The response includes a payment.invoice — that’s a BOLT-11 invoice string. Display it as a QR code for the customer to scan.

Step 2: Redirect to hosted checkout

The easiest option: redirect your customer to our hosted checkout page. It shows the QR code, handles wallet deep links, and auto-detects payment.

// After creating the payment, redirect:
res.redirect(`https://pay.lnmerchant.com/checkout/${payment.id}`);

The checkout page shows the amount, a QR code, and a “Waiting for payment…” indicator that automatically updates when the customer pays.

Step 3: Detect settlement

Poll the payment status or set up a webhook. The payment moves from pending to settled when the Lightning invoice is paid.

Option A: Poll

async function waitForPayment(paymentId) {
  while (true) {
    const res = await fetch(`https://api.lnmerchant.com/payments/${paymentId}`, {
      headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
    });
    const payment = await res.json();

    if (payment.status === 'settled') {
      return payment; // Payment confirmed!
    }

    await new Promise(r => setTimeout(r, 3000)); // Check every 3 seconds
  }
}

Configure a webhook URL in your LN Merchant dashboard. We’ll POST to your endpoint when the payment settles:

{
  "event": "payment.settled",
  "paymentId": "abc-123",
  "currency": "BTC",
  "amountSats": 26315,
  "amountCents": 2500,
  "status": "settled",
  "timestamp": "2026-04-28T14:30:00Z"
}

Verify the X-Webhook-Signature header (HMAC-SHA256) to ensure the request is authentic.

Step 4: Confirm the purchase

Once the payment is settled, confirm the purchase in your app — grant access, book the reservation, ship the product, whatever your business does.

app.post('/webhook', (req, res) => {
  const { event, paymentId, status } = req.body;

  if (event === 'payment.settled') {
    // Confirm the purchase in your database
    confirmPurchase(paymentId);
  }

  res.sendStatus(200);
});

Want USDC instead?

Same API, different currency. Just change currency: 'BTC' to currency: 'USDC' and you get a Solana Pay URL instead of a Lightning invoice. The checkout page handles both.

// Same code, just change the currency
body: JSON.stringify({
  currency: 'USDC',
  amountCents: 2500,
  description: 'Premium membership',
})
// Returns paymentUrl (Solana Pay) instead of invoice (BOLT-11)

What’s next

  • Auth & Capture: Hold funds before completing a booking with type: 'hold'
  • Subscriptions: Set up recurring Lightning billing
  • Refunds: Process refunds via reverse Lightning invoices

Ready to get started? Join the waitlist for early access to the API.

Ready to accept Lightning & USDC payments?

Join the waitlist for early access.

Get Early Access