What actually happens when you zap someone
- You tapped a lightning bolt
- What has to be in place first
- From button press to settled payment
- Who do you actually trust?
- Custodial vs non-custodial: what you’re actually choosing
- Why your zap didn’t show up
- The #privacy angle
- Six systems, one tap
You tapped a lightning bolt
You see a post on #nostr. You tap the zap button. A little animation plays. 21 sats gone. The whole interaction takes about two seconds and feels like pressing a like button that costs money.
It is not a like button. Between your tap and that receipt appearing on the post, at least five different systems talked to each other. An HTTP request left your client. A server validated a cryptographic event. A Lightning invoice was generated and paid. A signed receipt was broadcast to relays. Other clients fetched that receipt and decided whether to trust it.
All of this is invisible. Most of the time it works. When it doesn’t, the failure is silent. Your sats leave and no zap shows up. Understanding the plumbing helps you figure out why, and it changes how you think about which wallet to use.
What has to be in place first
Before a zap can happen, the recipient needs a #lightning address in their profile. This is the lud16 field in their kind 0 metadata, something like user@coinos.io or user@walletofsatoshi.com.
A Lightning address looks like an email address but it is a URL in disguise. user@coinos.io resolves to https://coinos.io/.well-known/lnurlp/user. Your client sends a GET request to that URL and gets back a JSON payload describing how to request invoices from the recipient’s wallet.
Two fields in that response matter for zaps. allowsNostr must be true. nostrPubkey must contain a valid hex public key. This is the key the recipient’s LNURL server will use to sign zap receipts. If either field is missing, your client cannot initiate a zap. It can still send a regular Lightning payment, the sats will arrive, but there will be no zap receipt on Nostr. Nobody on the network will know the payment happened. This is the first place zaps silently fail.
Not every Lightning wallet supports these fields. If you set up a Lightning address with a provider that hasn’t implemented NIP-57, your profile will accept payments but not zaps. The difference is invisible until someone tries to zap you and nothing shows up.
From button press to settled payment
Here is the full path, step by step.
1. Your client builds a zap request. When you tap the zap button, your client creates a kind 9734 event. This event is not published to relays. It contains your pubkey, the recipient’s pubkey in a p tag, the event being zapped in an e tag, the amount in millisatoshis, and a list of relays where the zap receipt should be published. You sign this event with your private key, or your NWC signer signs it for you.
2. The zap request goes to the LNURL server. Your client sends an HTTP GET request to the recipient’s LNURL callback URL. The signed kind 9734 event is passed as a URL-encoded JSON string in a nostr query parameter, along with the amount in millisats. This is where the protocol leaves Nostr and enters HTTP. The zap request is not a relay message. It is a web request to the recipient’s wallet service.
3. The server validates and generates an invoice. The LNURL server checks the zap request: valid signature, correct pubkey, amount within the allowed range. If everything passes, it generates a BOLT11 #lightning invoice. The invoice’s description hash is set to the SHA256 of the zap request event JSON. This is how the invoice is cryptographically tied to the specific zap. No other invoice can satisfy this zap request.
4. Your wallet pays the invoice. The client receives the BOLT11 invoice in the server’s HTTP response. If the client has built-in wallet access, it pays directly. More commonly, it hands the invoice to a connected wallet via NIP-47 (Nostr Wallet Connect). NWC uses kind 23194 and 23195 events encrypted over relays so the wallet never needs to see your Nostr identity key. This is where the actual #bitcoin payment happens over the Lightning Network.
5. The server publishes a zap receipt. Once the payment settles, the recipient’s LNURL server creates a kind 9735 event: the zap receipt. It includes a bolt11 tag with the paid invoice, a description tag containing the original zap request JSON, and the recipient’s pubkey. The server signs this event with its nostrPubkey and publishes it to the relays listed in the zap request.
6. Clients fetch and display the zap. Other clients see the kind 9735 event on relays. They validate it by checking that the receipt’s signing key matches the recipient’s LNURL server nostrPubkey, that the invoice amount matches the zap request amount, and that the description hash lines up. If everything checks out, the zap appears on the post.
Six steps. Three protocols (Nostr, HTTP/LNURL, Lightning). Two event kinds. One invoice. The whole thing usually completes in under five seconds.
Who do you actually trust?
Here is the part that most explanations skip.
The zap receipt is not a proof of payment. The NIP-57 spec says this directly: a zap receipt only proves that a Nostr user fetched an invoice. The existence of the receipt implies the invoice was paid, but a rogue LNURL server could fabricate receipts for invoices that were never paid, or suppress receipts for invoices that were.
You trust the LNURL server. That’s the deal. The server receives the payment, decides the payment settled, creates the receipt, signs it, and publishes it. If the server lies, there is no on-chain proof to contradict it. The cryptography in NIP-57 ensures that only the designated server can sign valid receipts. It does not ensure that the server is honest.
For most people using custodial wallets like Wallet of Satoshi, Coinos, or Primal’s built-in wallet, the LNURL server and the wallet are the same entity. They generate the invoice, receive the payment, sign the receipt. You trust them for the entire chain.
For self-hosted setups with Alby Hub, LNbits, or a BTCPay Server plugin, you run the LNURL server yourself. You sign your own receipts. The trust is in your own infrastructure, which is better but means your server needs to be online and properly configured for zaps to work.
NIP-61 nutzaps offer a different model. Instead of routing through an LNURL server, the sender mints #cashu ecash tokens locked to a public key the recipient controls. The payment is the receipt. No intermediary signs anything. The tradeoff is that nutzaps require both parties to trust the same ecash mint, and client support is still limited.
Custodial vs non-custodial: what you’re actually choosing
The wallet you use determines where your sats live and who signs your zap receipts.
Custodial wallets like Coinos, Wallet of Satoshi, and Primal’s built-in wallet are the easiest path. Set a Lightning address in your profile and zaps work immediately. The tradeoff: the service holds your sats. They could go offline, get hacked, or shut down. Alby’s shared custodial wallet shut down on January 4, 2025. Mutiny Wallet, one of the few self-custodial wallets with NWC support for Nostr zapping, shut down at the end of 2024. Services disappearing is not hypothetical.
Self-custodial options exist but require more effort. Alby Hub replaced Alby’s custodial wallet with a self-hosted Lightning node you control. It supports NWC natively, so Nostr clients can request payments without seeing your keys. Phoenix and Breez offer mobile self-custody. The setup is harder and your node needs to be reachable, but your sats are yours.
NWC acts as a bridge. Nostr clients like Amethyst, Damus, and Primal support NIP-47, which lets you connect any NWC-compatible wallet for outgoing zaps while keeping a custodial Lightning address for receiving. This splits the trust: your outbound payments come from your own wallet, but incoming zaps still route through whatever service hosts your Lightning address.
Why your zap didn’t show up
Zaps fail silently. The sats leave your wallet and nothing appears on the post. Here are the actual reasons.
The recipient’s LNURL server doesn’t support NIP-57. allowsNostr is false or nostrPubkey is missing. The payment goes through as a regular Lightning transaction. The sats arrive but no zap receipt is created.
Relay mismatch. The zap receipt was published to relays that the recipient’s client isn’t connected to. The receipt exists somewhere on the network, but the client never sees it. This is probably the most common silent failure.
The LNURL server failed to publish the receipt. Some LNbits and BTCPay Server configurations have had bugs where the payment settles but the kind 9735 event is never broadcast. The sats arrive, the receipt doesn’t.
Invalid receipt. The server generated a receipt with missing or incorrect tags. Clients that validate strictly will reject it. Clients that don’t validate will display it, which is its own problem since it means they’ll also display fabricated receipts.
Amount mismatch. If the amount in the zap request doesn’t match the amount in the BOLT11 invoice, strict clients will reject the receipt even though the payment went through.
Timing. Zap receipts are not instant. The payment has to settle, the server has to create and sign the event, and it has to propagate through relays. A few seconds of delay is normal. Sometimes the relay is slow or the client needs a manual refresh.
The #privacy angle
Every public zap creates a kind 9735 event that anyone can read: sender pubkey, recipient pubkey, amount, timestamp. Every public zap is an edge in a financial graph permanently tied to your identity.
NIP-57 defines anonymous zaps where the sender’s pubkey is hidden. The client creates the zap request with a throwaway key and destroys it after posting. The recipient and the public see the sats but not who sent them. Some clients also support private zaps where only the recipient can see the sender’s identity.
I covered the #privacy implications of zap patterns in detail in my article on pseudonymous identity opsec. The short version: if your pseudonymous identity consistently zaps the same accounts that your real identity follows, that overlap is a correlation waiting to be noticed. Use anonymous zaps if you care about this. Most people don’t, and that’s a reasonable choice for small amounts.
#cashu nutzaps (NIP-61) offer a different privacy tradeoff. The payment doesn’t touch the Lightning Network, so there’s no cross-layer analysis between on-chain and Lightning channels. But the tokens are visible on Nostr relays and the mint can see redemption patterns.
Six systems, one tap
A zap looks like tapping a button. Behind it: LNURL resolution, zap request creation, an HTTP callback, invoice generation, a Lightning payment, and a zap receipt broadcast. Six systems that have to cooperate for a number to show up next to a lightning bolt icon.
It works surprisingly well for how many moving parts are involved. But the trust model is worth understanding. You trust the LNURL server to honestly report payments. You trust relays to deliver the receipt. You trust clients to validate what they display. When zaps break, the failure is almost always silent, and knowing this flow is how you debug it.
Pick your wallet setup with the trust model in mind, not just the convenience. And if someone zaps you and it doesn’t show up, now you know at least six places to look.
#nostr #lightning #bitcoin #nip57
Write a comment