Skip to main content

NIP-57: Lightning Zaps

NIP-57 defines how Lightning Network payments (zaps) work on Nostr, enabling users to tip content creators with Bitcoin.

Summary

AspectDetail
Kinds9734 (request), 9735 (receipt)
PurposeBitcoin tips via Lightning
StatusMerged
Depends onNIP-01, LNURL

Overview

Zaps are Lightning payments tied to Nostr events:

  • 9734: Zap Request (initiates payment)
  • 9735: Zap Receipt (proves payment)

Zap Request (kind 9734)

Created by the sender's client:

{
"kind": 9734,
"pubkey": "sender_pubkey",
"created_at": 1234567890,
"content": "Great post! 🔥",
"tags": [
["p", "recipient_pubkey"],
["e", "event_id_being_zapped"],
["amount", "1000000"],
["relays", "wss://relay1.com", "wss://relay2.com"],
["lnurl", "lnurl1..."]
]
}

Required Tags

TagDescription
pRecipient's pubkey
relaysWhere to publish receipt

Optional Tags

TagDescription
eEvent being zapped
aParameterized replaceable event
amountAmount in millisatoshis
lnurlRecipient's LNURL

Content

Optional message from zapper to recipient.

Zap Receipt (kind 9735)

Created by the LNURL provider after payment:

{
"kind": 9735,
"pubkey": "lnurl_provider_pubkey",
"created_at": 1234567890,
"content": "",
"tags": [
["p", "recipient_pubkey"],
["P", "sender_pubkey"],
["e", "zapped_event_id"],
["bolt11", "lnbc1000n1..."],
["description", "<stringified kind 9734 event>"],
["preimage", "payment_preimage"]
]
}

Tags Explained

TagDescription
pRecipient (lowercase)
PSender (uppercase)
eZapped event
bolt11Lightning invoice
descriptionOriginal zap request (stringified)
preimagePayment proof

Flow

LNURL Integration

Recipient Setup

Profile (kind 0) must include lud16 or lud06:

{
"name": "Alice",
"lud16": "alice@getalby.com"
}

LNURL Callback

The LNURL service must:

  1. Accept the zap request in nostr query parameter
  2. Validate the request
  3. Generate Lightning invoice
  4. Publish zap receipt after payment

Callback URL

GET https://service.com/callback?
amount=1000000&
nostr=<url-encoded-kind-9734>&
lnurl=<original-lnurl>

Validation

For Zap Receipts

Clients MUST verify:

  1. Receipt signature is valid
  2. description contains valid kind 9734
  3. Zap request signature is valid
  4. p tag matches request
  5. e or a tag matches (if present)
  6. preimage matches invoice (if present)

Invalid Receipts

Discard receipts where:

  • Signatures don't match
  • Request was modified
  • Tags don't align

Anonymous Zaps

Sender can hide identity:

  1. Generate ephemeral keypair
  2. Sign request with ephemeral key
  3. Don't include identifying info

Receipt will show ephemeral pubkey, hiding true sender.

Private Zaps

For enhanced privacy (not fully standardized):

  • Encrypt the zap request
  • Only recipient can see sender
  • Amount still visible

Implementation

Sending a Zap

async function sendZap(recipientPubkey, eventId, amount, message) {
// 1. Get recipient's LNURL
const profile = await fetchProfile(recipientPubkey);
const lnurl = profile.lud16 || profile.lud06;

// 2. Create zap request
const zapRequest = {
kind: 9734,
pubkey: myPubkey,
created_at: Math.floor(Date.now() / 1000),
content: message,
tags: [
['p', recipientPubkey],
['e', eventId],
['amount', String(amount * 1000)],
['relays', 'wss://relay.damus.io'],
['lnurl', lnurl]
]
};

zapRequest.id = getEventHash(zapRequest);
zapRequest.sig = signEvent(zapRequest, myPrivkey);

// 3. Get invoice from LNURL
const callbackUrl = await getLnurlCallback(lnurl);
const response = await fetch(
`${callbackUrl}?amount=${amount * 1000}&nostr=${encodeURIComponent(JSON.stringify(zapRequest))}`
);
const { pr: invoice } = await response.json();

// 4. Pay invoice
await wallet.payInvoice(invoice);
}

Receiving Zaps

async function countZaps(eventId) {
const receipts = await fetchEvents({
kinds: [9735],
'#e': [eventId]
});

let total = 0;
for (const receipt of receipts) {
if (validateZapReceipt(receipt)) {
const amount = extractAmount(receipt);
total += amount;
}
}

return total;
}

Resources


Milestone

Zaps reached 1 million transactions in June 2023, demonstrating demand for social micropayments.