ZapAPI Docs
Get StartedConceptsAI GatewayGuidesPayment GatewaySDKAPI ReferenceResources
Payment Gateway

Lightning Setup

LNbits, node options, environment variables, webhooks and costs.

What to set up, how to set it up — from local dev to production.

Architecture choice: LNbits-first

ZapAPI ──(REST, X-Api-Key)──> LNbits ──(funding source)──> Lightning Node
  • LNbits = wallet account system + LNURL extension + multi-wallet isolation
  • Funding source = the actual Lightning node holding liquidity (LND/CLN/Phoenixd/hosted)

1. Environments

EnvLNbitsNodeNetwork
Local devDocker LNbitsPolar/regtest or Mutinynetregtest/signet
Stagingstaging.lnbits.zapapi.comMutinynet or small mainnetsignet/mainnet-small
Productionlnbits.zapapi.com (self-host, DO/AWS)Voltage LND or self-host LNDmainnet

Why Voltage for the node (research-backed)

  • Managed LND in minutes, no blockchain sync wait, you keep keys, no KYC
  • ~$30–100/mo depending on channel liquidity
  • Alternative: self-host LND on a $20 VPS + ThunderHub for ops

2. Local Development Setup

# Option A — quickest: hosted LNbits demo (demo.lnbits.com) — OK for hacking, NOT prod
# Option B — Docker LNbits (recommended)

# Add to docker-compose.yml:
lnbits:
 image: lnbits/lnbits:latest
 ports: ["5000:5000"]
 environment:
 LNBITS_BACKEND_WALLET_CLASS: VoidWallet # fake wallet for pure API testing
 LNBITS_DATA_FOLDER: ./data
 LNBITS_ADMIN_USERS: "" # set your user id after first login
 LNBITS_EXTENSIONS: "lnurlp" # enable LNURL extension
 volumes: [lnbits-data:/data]

Dev with fake payments: VoidWallet makes LNbits behave fully but settle instantly — perfect for unit/e2e tests.

For real Lightning in dev: use Mutinynet (signet with LN) via hosted lnbits.com or Alby test accounts.


3. Production LNbits Setup

# docker-compose.prod.yml (on a dedicated VPS, 2GB RAM min)
lnbits:
 image: lnbits/lnbits:latest
 restart: always
 environment:
 LNBITS_BACKEND_WALLET_CLASS: LndRestWallet
 LND_REST_ENDPOINT: https://your-node:8080/
 LND_REST_CERT: /lnd/tls.cert
 LND_REST_MACAROON: /lnd/admin.macaroon
 LNBITS_DATA_FOLDER: ./data
 LNBITS_ADMIN_USERS: <comma-separated-admin-user-ids>
 LNBITS_ALLOWED_USERS: <restrict account creation in prod>
 LNBITS_EXTENSIONS: "lnurlp,withdraw" # + any others needed
 LNBITS_SITE_TITLE: "ZapAPI Treasury"
 LNBITS_DISABLED_EXTENSIONS: "admin-ng" # lock down what you don't use
 volumes:
 - lnbits-data:/data
 -./lnd:/lnd:ro

Hardening checklist

  • [] Behind nginx/Caddy with TLS only
  • [] Not publicly exposed for account creation (LNBITS_ALLOWED_USERS) — ZapAPI server is the only creator of wallets (admin UI locked to our IPs)
  • [] Postgres backend for LNbits in prod (default SQLite won't scale) LNBITS_DATABASE_URL=postgres://...
  • [] Daily backup of LNbits DB + macaroons in secrets manager
  • [] Separate macaroon scopes: invoice-only for hot paths, admin for wallet creation

4. ZapAPI LNbits Integration (already built — config recap)

Each ZapAPI provider record stores encrypted:

{ "adminKey": "…", "invoiceKey": "…" } // per-user wallet keys
  • invoiceKey create/check invoices (used in hot path)
  • adminKey pay invoices (withdrawals), create LNURL links
  • Encryption: AES-256-CBC with ENCRYPTION_KEY env (32-byte hex)

Per-user wallet provisioning (to implement in Phase 1)

on user signup:
 1. POST /api/v1/account (LNbits superuser) create wallet "user_<id>"
 2. store wallet_id + adminkey + inkey (encrypted) on user_wallet row
 3. LightningAddress row created when user claims username

5. Webhooks

Inbound (LNbits ZapAPI) IMPLEMENTED

POST /api/v1/webhooks/lnbits/:token? — receives settled-payment notifications.

Setup: in each LNbits wallet's settings, set the webhook URL:

https://api.zapapi.com/api/v1/webhooks/lnbits/<LNBITS_WEBHOOK_SECRET>

Set LNBITS_WEBHOOK_SECRET in server env (random 32+ char string). In dev, leave it unset to skip verification.

On each settled payment the handler fans out (failure-isolated):

  • invoices markAsPaid (project invoices from the /invoices API)
  • zaps settle + publish NIP-57 receipt instantly (30s cron remains as backstop)
  • withdrawals reconcile outgoing payments (preimage/fee)

Idempotent: already-settled records are skipped.

Outbound (ZapAPI merchant)

  • Merchant registers URL per project
  • Every delivery signed: X-ZapAPI-Signature: t=<unix>,v1=<hmac_sha256(secret, t + "." + rawBody)>
  • Retries: 5 attempts, exponential backoff (1m, 5m, 30m, 2h, 8h) via existing Bull queue
  • Delivery log + replay button in dashboard (Phase 3)

6. Lightning Address / LNURL endpoints IMPLEMENTED

Status: built (Phase 1.1–1.3, 1.5). See server/src/lnurl/ and client/app/.well-known/.

Serving topology (Vercel):

wallet https://zapapi.com/.well-known/lnurlp/alice (Next.js route handler)
 http://api.zapapi.com/api/v1/lnurl/params/alice (NestJS, X-Served-Domain)

Env vars:

# server
PRIMARY_DOMAIN=zapapi.com # default domain for addresses
SERVED_DOMAINS=zapapi.com,zapapi.io # multi-domain allowlist
PUBLIC_URL=https://zapapi.com # fallback callback base URL
LNURL_MIN_SENDABLE_MSAT=1000
LNURL_MAX_SENDABLE_MSAT=100000000000
LNURL_COMMENT_ALLOWED=280
NOSTR_RELAYS=wss://relay.damus.io,wss://nos.lol,wss://relay.primal.net
NOSTR_ZAP_SIGNING_KEY=<64-hex privkey> # platform key that signs zap receipts (NIP-57)

# client (Vercel)
API_URL=https://api.zapapi.com/api/v1 # server-side proxy target
MIGRATED_DOMAINS= # old domains 301 to PRIMARY_DOMAIN

Endpoints:

GET /.well-known/lnurlp/:username LUD-06 params (+allowsNostr/nostrPubkey for zaps)
GET /lnurl/callback/:username fresh BOLT11 (description_hash for NIP-57 zaps)
GET /.well-known/nostr.json?name= NIP-05 {names, relays}
GET /api/v1/lnurl/availability/:u dashboard username check

Note: LNbits lnurlp extension can also serve these, but we implement them in ZapAPI so we control zap validation, CRM capture, and analytics — LNbits stays a pure wallet backend.


7. Liquidity & Ops

ConcernApproach
Inbound liquidityOpen channels to well-connected nodes (ACINQ, Kraken, Wallet of Satoshi) or buy inbound via Lightning Pool/Magma
MonitoringNode balance alerts, LNbits uptime check, invoice failure rate
BackupsLNbits DB daily, LND SCB (static channel backup) after every channel change
Custody ceilingAlert when total user balances > threshold; encourage auto-sweep

8. Costs (rough monthly, production)

ItemCost
VPS for LNbits (4GB)$20–40
Voltage LND node$30–100 + channel capital
Postgres (existing)$0 (shared)
Channel liquidity (one-time capital)0.05–0.5 BTC depending on volume
Total fixed~$50–150/mo to start

On this page