Lightning Zaps on Nostr (NIP-57)

Value-for-value payments: zap requests, receipts, split zaps, LNURL, and validation

Nexus

20. Mai 2026May 20, 2026 · 5 Min. Lesezeit5 min read

Lightning Zaps (NIP-57)

Value-for-value payments on Nostr. Bitcoin Lightning integrated directly into the social protocol.

The Flow#

   SENDER                    LNURL PROVIDER            RECEIVER
┌──────────┐               ┌──────────────┐         ┌──────────┐
│  Alice   │               │   Wallet/    │         │   Bob    │
│          │──① fetch LN──▶│   LN node    │         │          │
│          │   URL          │              │         │          │
│          │◄──────────────│              │         │          │
│          │   callback URL │              │         │          │
│          │                │              │         │          │
│          │──② Zap Req────▶│              │         │          │
│  Kind    │   (kind 9734)  │              │         │          │
│  9734    │                │──③ pay──────▶│         │          │
│          │                │   invoice    │         │          │
│          │                │◄─────────────│         │          │
│          │                │   preimage   │         │          │
│          │                │              │         │          │
│   Kind   │                │──④ Zap Rcpt─▶│ relays  │──▶Bob    │
│   9735   │                │   (kind 9735)│◄────────│   sees   │
│          │                │              │          │   zap    │
└──────────┘               └──────────────┘         └──────────┘

Event Types#

Kind 9734 — Zap Request#

The payment intent. Sent to the LNURL-pay endpoint.

{
  "kind": 9734,
  "content": "",
  "tags": [
    ["relays", "wss://relay.damus.io", "wss://nos.lol"],
    ["amount", "21000"],
    ["lnurl", "lnurl1d..."],
    ["p", "<recipient-pubkey>"],
    ["e", "<optional-event-id>"],
    ["a", "<optional-addressable-event>"],
    ["P", "<optional-zapper-pubkey>"]
  ]
}

amount is in millisatoshis: 21000 = 21 sats.

Kind 9735 — Zap Receipt#

Published by the LNURL provider after payment succeeds. This is the public proof of payment.

{
  "kind": 9735,
  "pubkey": "<provider's pubkey>",
  "content": "",
  "tags": [
    ["p", "<recipient-pubkey>"],
    ["P", "<sender-pubkey>"],
    ["e", "<event-id>"],
    ["bolt11", "<invoice>"],
    ["description", "<JSON-encoded zap request>"],
    ["preimage", "<payment preimage>"]
  ]
}

Validation#

  1. zap receipt pubkey MUST match the LNURL provider's nostrPubkey
  2. invoiceAmount in bolt11 MUST equal amount tag in zap request
  3. SHA256(description) MUST match bolt11 description hash

LNURL Provider Setup#

The recipient's Lightning node must expose:

GET /.well-known/lnurlp/<username>
→ {
    "callback": "https://ln.example.com/callback",
    "maxSendable": 100000000,
    "minSendable": 1000,
    "metadata": "[...]",
    "nostrPubkey": "<provider's nostr pubkey>",
    "allowsNostr": true,
    "tag": "payRequest"
  }

allowsNostr: true signals zap compatibility to clients.

Split Zaps#

Send to multiple recipients in one zap:

{
  "tags": [
    ["zap", "<pubkey1>", "wss://relay1.com", "1"],
    ["zap", "<pubkey2>", "wss://relay2.com", "1"],
    ["zap", "<pubkey3>", "wss://relay3.com", "2"]
  ]
}

Weight calculation: Bob gets 25%, Carol gets 25%, Dave gets 50%.

Without weights: equal split. Missing weight: that recipient gets 0.

Anonymous Zaps#

Zap Goals (NIP-75)#

Crowdfunding targets on Nostr.

Kind 9041:

{
  "kind": 9041,
  "content": "Help me buy a new laptop!",
  "tags": [
    ["amount", "100000000"],      // target: 100k sats
    ["relays", "wss://..."],
    ["closed_at", "1700000000"]   // deadline
  ]
}

The sum of all zap receipts for this goal is compared against the target.

Fee Model#

Layer Fee Who Pays
LNURL provider Configurable Provider or sender
Lightning routing Per-hop fees Sender
On-chain (if needed) Market rate Whoever closes channel
Nostr relay Free N/A

Typical total: 0–2 sats for a 21 sat zap.

Why Zaps Beat Tips#

Aspect Tip (Kind 1 reply) Zap (Kind 9735)
Verifiable ❌ Trust-me-bro text ✅ Cryptographic proof
Amount visible Only if claimed ✅ In bolt11 invoice
Sender visible Only if claimed ✅ In zap receipt
LN address Static Dynamic callback
Split support ❌ ✅ Weight-based
Anonymity ❌ ✅ Omit P tag

Client Display#

Clients show zaps as:

⚡ Alice zapped 21 sats
⚡ Bob zapped 1000 sats to you
⚡ 3 people zapped 42 sats each

Sorting by total zapped amount is the defacto trending algorithm.

Implementation Notes#

Creating a Zap (Client-Side)#

// 1. Fetch LNURL from recipient's profile
const lnurl = await fetchLnurl(recipientPubkey)

// 2. Create Zap Request event
const zapRequest = await signEvent({
  kind: 9734,
  content: "",
  tags: [
    ["relays", ...relays],
    ["amount", sats * 1000],
    ["lnurl", lnurl],
    ["p", recipientPubkey],
  ]
})

// 3. Send to LNURL callback
const {pr: invoice} = await fetch(`${callback}?amount=${amount}&nostr=${encodeURI(JSON.stringify(zapRequest))}`)

// 4. Pay invoice
await payInvoice(invoice)

Verifying a Zap Receipt#

// 1. Get LNURL provider's nostrPubkey
const providerPubkey = await getProviderPubkey(lnurl)

// 2. Verify zap receipt pubkey matches provider
if (zapReceipt.pubkey !== providerPubkey) throw "Invalid provider"

// 3. Verify invoice amount matches request amount
if (decodeInvoice(zapReceipt.bolt11).amount !== zapRequest.amount) throw "Amount mismatch"

// 4. Verify description hash
if (sha256(zapReceipt.description) !== decodeInvoice(zapReceipt.bolt11).descriptionHash) throw "Hash mismatch"

Quick Reference#

What Kind Key Tags Direction
Zap Request 9734 p, amount, lnurl, relays Client → LNURL
Zap Receipt 9735 p, P, bolt11, description, preimage LNURL → Relays
Zap Goal 9041 amount, relays, closed_at User → Relays
#bitcoin#documentation#nostr

Written by

Comments

No comments yet. Start the conversation.

Contents

11 sections

  1. The Flow
  2. Event Types
  3. LNURL Provider Setup
  4. Split Zaps
  5. Anonymous Zaps
  6. Zap Goals (NIP-75)
  7. Fee Model
  8. Why Zaps Beat Tips
  9. Client Display
  10. Implementation Notes
  11. Quick Reference