1 Overview
A nutzap sends ecash to another user over Nostr. The sender mints a Cashu token at a mint the recipient trusts. The sender locks the token to a public key the recipient controls. The sender then publishes the token inside a Nostr event.
The lock uses P2PK (pay-to-public-key, Cashu NUT-11). A P2PK-locked token can be spent only by the holder of the matching private key. So the published event is safe to show in public. It is money and proof of payment at the same time. No invoice, no callback server, and no receipt event from a third party are needed. Compare this with Lightning zaps in NIP-57, which need a server to issue receipts.
This NIP defines two events. kind:10019 tells the world how to send money to a user. kind:9321 carries the locked tokens to the recipient. Redemption reuses the kind:7376 spending-history event from NIP-60.
Read NIP-60 first. It defines the wallet event that stores the private key nutzaps are locked to, and the token and history events a wallet uses. NIP-61 is the "receive money" side of that wallet.
2 The Nutzap Info Event — Kind 10019
kind:10019 is a replaceable event. It tells other users how to send money to its author. A sender MUST read this event before sending a nutzap.
{
"kind": 10019,
"tags": [
["relay", "wss://relay1"],
["relay", "wss://relay2"],
["mint", "https://mint1", "usd", "sat"],
["mint", "https://mint2", "sat"],
["pubkey", <p2pk-pubkey>]
]
}
| Tag | Value | Rule |
|---|---|---|
| relay | relay URL | A relay the user reads token events from. Senders should write nutzap events to these relays. Repeat the tag for each relay. |
| mint | mint URL, then base units | A mint the user explicitly agrees to receive funds on. Extra values list the base units the mint supports, such as usd or sat. Clients SHOULD NOT send money on a mint that is not listed here. Doing so risks burning the money. |
| pubkey | public key, hex | The key that MUST be used to P2PK-lock incoming nutzaps. See the lock rules below. |
P2PK lock rules
The lock target is strict. Follow these rules exactly:
- Lock to the key in the
pubkeytag of the recipient'skind:10019. This key corresponds to theprivkeyfield encrypted inside the recipient's NIP-60 wallet event (kind:17375). - Implementations MUST NOT lock to the recipient's main Nostr public key.
- When building the P2PK lock, clients MUST prefix the public key with
"02". Cashu uses 33-byte compressed keys; Nostr keys are 32 bytes. The prefix keeps nostr and cashu compatible.
Never lock a token to the recipient's Nostr identity key. The wallet's separate P2PK key exists so the user can spend ecash without exposing the identity key to wallet code, and can rotate it independently.
3 The Nutzap Event — Kind 9321
kind:9321 is the nutzap itself. The sender publishes it and p-tags the recipient. Its proofs are P2PK-locked to the key the recipient listed in kind:10019.
{
"kind": 9321,
"content": "Thanks for this great idea.",
"pubkey": <sender-pubkey>,
"tags": [
["proof", "{\"amount\":1,\"C\":\"02277c…6d3f\",\"id\":\"000a93d6f8a1d2c4\",
\"secret\":\"[\\\"P2PK\\\",{\\\"nonce\\\":\\\"b00b…ee83\\\",
\\\"data\\\":\\\"02eaee…c1ed\\\"}]\"}"],
["unit", "sat"],
["u", "https://stablenut.umint.cash"],
["e", <nutzapped-event-id>, <relay-hint>],
["k", <nutzapped-kind>],
["p", <recipient-pubkey>]
]
}
| Field / Tag | Required | Rule |
|---|---|---|
| content | optional | A comment for the nutzap. May be empty. |
| proof | one or more | A Cashu proof, JSON-stringified. It MUST be P2PK-locked to the recipient's kind:10019 pubkey and MUST include a DLEQ proof (Cashu NUT-12). |
| unit | optional | The base unit of the proofs, such as sat, usd, or eur. Defaults to sat when omitted. |
| u | required | The URL of the mint, written EXACTLY as it appears in the recipient's kind:10019. |
| e | optional | The event that is nutzapped, if any, with an optional relay hint. |
| k | optional | The kind of the nutzapped event. |
| p | required | The Nostr identity public key of the nutzap recipient. |
The source spec shows the k tag in its kind:9321 example but never defines it in the tag list. It was added in 2025 to match other reaction-style events; the meaning here is inferred. The prose for the u tag is also garbled in the source ("is the mint the URL of the mint").
4 Sending a Nutzap
Follow this procedure to send a nutzap:
- Fetch the recipient's
kind:10019event. - Mint new ecash, or swap ecash you already hold, on one of the mints the recipient lists. P2PK-lock the outputs to the recipient's listed
pubkey, with the"02"prefix. - Build a
kind:9321event with the proofs, theumint tag, and theptag. Addeandktags when you zap a specific event. - Publish the event to the relays the recipient listed in
kind:10019.
A nutzap MUST use a mint from the recipient's kind:10019 and MUST reach the recipient's relays. Break either rule and the recipient may never see the event. The tokens are then donated to the mint forever.
5 Receiving and Redeeming
The recipient's client polls its relays for nutzaps. Clients should send a REQ that filters:
- with
#pfor the user's own pubkey; - with
#ufor the mints the user expects ecash from. This stops the client from interacting with mints the user never signaled; - with
sinceset to thecreated_atof the user's most recentkind:7376event. That event marks the last redeemed nutzap. Clients may use other markers, including internal state; this is one possible approach.
{ "kinds": [9321], "#p": ["my-pubkey"], "#u": [<mint-1>, <mint-2>],
"since": <latest-created_at-of-kind-7376> }
On each new nutzap, the client swaps the locked proofs into a wallet the user controls. That wallet can be a NIP-60 wallet, the user's own Lightning wallet, or anything else.
Recording the redemption — kind 7376
When it claims a token, the client SHOULD create a kind:7376 spending-history event (defined in NIP-60) and e-tag the original nutzap. This records that the token is already claimed, so no client tries again. It also signals to the sender that the ecash was redeemed. One kind:7376 event may tag multiple kind:9321 events.
{
"kind": 7376,
"content": nip44_encrypt([
["direction", "in"], // in = received, out = sent
["amount", "1"],
["unit", "sat"],
["e", <7375-event-id>, <relay-hint>, "created"] // new token event
]),
"tags": [
["e", <9321-event-id>, <relay-hint>, "redeemed"], // nutzap redeemed
["p", <sender-pubkey>] // author of the 9321 event
]
}
The encrypted content lists the direction (in for received), the amount, the unit, and an e tag with marker created pointing to the new kind:7375 token event. The unencrypted tags carry the redeemed nutzap with marker redeemed and the sender's pubkey. Publish redemption events to the sender's NIP-65 "read" relays, so the sender learns the money arrived.
6 Verifying a Nutzap
Any observer client can count the nutzaps an event received. Before it lists or counts a nutzap, the observer SHOULD run four checks:
- Check that the receiving user issued a
kind:10019that tags the mint where the ecash was minted. - Check that the token is locked to the pubkey the user listed in that
kind:10019. - Check the
utag: the token must be issued by one of the mints listed in thekind:10019. - Verify the DLEQ proof of the tokens locally.
All four checks work offline. The observer only needs the receiver's kind:10019 event and the mint's keyset. So verification is reasonably fast.
7 Final Considerations
- Clients SHOULD guide users to list only mints compatible with NUT-11 (P2PK) and NUT-12 (DLEQ proofs) in their
kind:10019. Otherwise anyone can spend the "locked" nutzaps. - Clients SHOULD normalize and deduplicate mint URLs, as described in NIP-65.
- A nutzap event MUST include proofs from one of the mints the recipient listed in their
kind:10019, and it MUST be published to the recipient's NIP-65 relays. Failure to do so may donate the tokens to the mint, because the recipient might never see the event.
The source spec names two different publish targets. The flow and the relay tag say: publish nutzaps to the relays in the recipient's kind:10019. The final considerations say: publish to the recipient's NIP-65 relays. Safe clients publish to both sets. Also, NIP-65 describes relay URL handling, not mint URL normalization; the reference is loose.
8 Worked Example
Alice liked Bob's note event-id-1. She nutzaps him 1 sat. The transcript below shows both sides. Orange lines go to a relay. Blue lines come from a relay.
-- Alice fetches Bob's nutzap info -- → ["REQ", "info", {"kinds":[10019], "authors":["<bob>"]}] ← ["EVENT", "info", {"kind":10019, "tags":[["relay","wss://relay1"], ["mint","https://stablenut.umint.cash","sat"], ["pubkey","eaee89…ac1ed"]], …}] -- Alice swaps 1 sat at that mint, locked to "02" + eaee89…ac1ed -- -- Alice publishes the nutzap to wss://relay1 -- → ["EVENT", {"kind":9321, "content":"Thanks for this great idea.", "tags":[["proof","{\"amount\":1,\"C\":\"02277c…6d3f\",\"id\":\"000a93d6f8a1d2c4\", \"secret\":\"[\\\"P2PK\\\",{\\\"nonce\\\":\\\"b00b…ee83\\\",\\\"data\\\":\\\"02eaee…c1ed\\\"}]\"}"], ["unit","sat"], ["u","https://stablenut.umint.cash"], ["e","event-id-1","wss://relay1"], ["k","1"], ["p","<bob>"]], …}] ← ["OK", "<nutzap-id>", true, ""] -- Bob's client polls for unredeemed nutzaps -- → ["REQ", "nz", {"kinds":[9321], "#p":["<bob>"], "#u":["https://stablenut.umint.cash"], "since":1749762600}] ← ["EVENT", "nz", {"kind":9321, …}] ← ["EOSE", "nz"] -- Bob swaps the proof into his NIP-60 wallet (new kind:7375), then records the redemption -- → ["EVENT", {"kind":7376, "content":"<nip44: direction=in, amount=1, unit=sat, e=<7375-id>/created>", "tags":[["e","<nutzap-id>","wss://relay1","redeemed"], ["p","<alice>"]], …}]
9 Version History
NIP-61 landed together with the NIP-60 Cashu wallet in late 2024 and was simplified heavily in early 2025. Notable changes, newest first:
- 20252025-10Added the
unittag to thekind:9321event, withsatas the default. - 20252025-08Added the missing
ktag to the nutzap example, matching other reaction-style events. - 20252025-02Removed the
atag from nutzap events; a series of wording nitpicks tightened the lock and verification rules. - 20252025-02Major simplification pass shared with NIP-60: the redemption flow settled on the
kind:7376history event. - 20252025Typo, JSON-format, and heading-level fixes; an unfinished sentence completed.
- Origin2024-10-25Pablo Fernandez proposed Cashu wallets and Nutzaps in one PR (
#1369).
Original Proposal - Credits
| Author | Pablo Fernandez |
| First commit | 2024-10-25 — “Cashu wallet + Nutzaps” (PR #1369) |
| Status | draft - optional — a P2PK-Cashu payment layer on top of NIP-60 |
| Source | 61.md on GitHub - full change history |
10 See Also
- NIP-60 — the Cashu wallet: the encrypted
privkey, token events (kind:7375), and history events (kind:7376). - NIP-65 — relay list metadata; redemption events go to the sender's read relays.
- NIP-57 — Lightning zaps; the server-based receipt flow nutzaps replace.
- NIP-44 — the encryption used for the
kind:7376content. - NIP-01 — events, tags, filters, and the replaceable storage class of
kind:10019.