Chapter 75 - Payments
75
Nostr Implementation Possibility - Hex № 75

Zap Goals

A fundraising target as a single event. Supporters zap the goal, and clients tally the receipts against the amount.

1 Overview

A zap goal is a fundraising target published as a Nostr event. The creator states a target amount and a description. Supporters contribute by zapping the goal event with the NIP-57 zap flow. Clients read the zap receipts and show a progress bar toward the target.

The goal event names the relays that collect its zap receipts. Every zap to the goal goes to those relays. A client can therefore tally the goal from a known, small set of relays. No payment server or crowdfunding platform is needed.

Goals also attach to other content. A long-form post, a badge, or a live stream can point at a goal with a goal tag. Clients then show the fundraiser next to that content.

Hint!

Read NIP-57 first. This NIP does not define a new payment path. It only defines the target event that existing zaps point at.

Creator kind 9041 Supporter zap Goal relays "relays" tag Client tally GOAL ZAP RECEIPTS kind 9735
Fig. 75-1 — The tally loop. The goal lists its relays. Zap receipts land there. A client sums them against the target amount.

2 The Goal Event

A zap goal is a kind:9041 event. This is a regular event under NIP-01 rules: relays store all goals, and a published goal is not replaceable. The content field holds a human-readable description of the goal.

Two tags are required:

Required tags on kind 9041
TagValueRule
amountinteger stringThe target amount in millisats.
relaysone or more relay URLsThe relays that zaps to this goal go to. Clients tally the goal from these relays. All URLs sit in this one tag.
Wire format - minimal goal event
{
  "kind": 9041,
  "tags": [
    ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...],
    ["amount", "210000"]
  ],
  "content": "Nostrasia travel expenses",
  // other NIP-01 fields: id, pubkey, created_at, sig
}

Three tags are optional:

Optional tags on kind 9041
TagValueRule
closed_atunix timestamp, secondsThe tally cutoff. Zap receipts published after this timestamp should not count toward the goal progress.
imageimage URLAn image for the goal.
summarystringA brief description, shorter than content.
Wire format - goal event with optional tags
{
  "kind": 9041,
  "tags": [
    ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...],
    ["amount", "210000"],
    ["closed_at", <unix timestamp in seconds>],
    ["image", <image URL>],
    ["summary", <description of the goal>]
  ],
  "content": "Nostrasia travel expenses",
  // other fields...
}

Two more tags may appear on the goal:

  • An r tag or an a tag. It links the goal to a URL or to an addressable event (see NIP-01).
  • One or more zap tags from NIP-57 Appendix G. They split the raised funds across multiple beneficiary pubkeys.
Tech Note

Two soft spots in the source spec. First, the closed_at cutoff filters receipts by when they are published, but a zap receipt's created_at is set by the lnurl server, so the exact clock to compare against is not defined. Second, relays, amount, and goal are multi-letter tag names, so relays do not index them under NIP-01; a client cannot query "all events for goal X" with a #goal filter and must scan or rely on the e tag in zap requests instead.

3 Linking Content to a Goal

An addressable event can link to a goal with a goal tag. The tag holds the goal's event id and an optional relay hint:

Wire format - addressable event pointing at a goal
{
  "kind": 3xxxx,
  "tags": [
    ["goal", <event id>, <relay URL (optional)>],
    // rest of tags...
  ],
  // other fields...
}

This makes the goal reusable. One fundraiser can appear on a long-form post, on a badge, and on a live stream at the same time. Each of those events carries the same goal tag.

Long-form post Live stream Badge Goal kind 9041 Alice Bob goal tag zap tags
Fig. 75-2 — One goal, many surfaces. Content links in with goal tags. Funds split out with zap tags.

4 Client Behavior

The source NIP sets three client rules:

Client rules
LevelRule
MAYDisplay funding goals on user profiles.
MUSTWhen zapping a goal event, copy the relays from the goal's relays tag into the relays tag of the NIP-57 zap request.
SHOULDWhen zapping an addressable event that carries a goal tag, put the goal's event id in the e tag of the zap request.
Warning!

The MUST rule is the whole tally mechanism. If a client zaps a goal but sends the receipt to other relays, the contribution exists on the network yet never shows in the progress bar. Always copy the goal's relays tag into the zap request.

The source lists two use cases. Fundraising clients build the whole experience around kind 9041. Content clients attach goals to events such as long-form posts, badges, or live streams.

5 Worked Example

Alice raises 210 000 sats for Nostrasia travel. She publishes a goal. Bob zaps it 21 000 sats. The transcript shows the goal, Bob's zap request, and the receipt that the tally counts.

Session transcript - goal, zap, tally
-- Alice publishes the goal (target in millisats) --
→ ["EVENT", {"id":"f9a02b6c11…","pubkey":"a1ice9f2…","kind":9041,
     "created_at":1749760000,
     "tags":[["relays","wss://alicerelay.example.com","wss://bobrelay.example.com"],
             ["amount","210000000"],
             ["closed_at","1752400000"],
             ["image","https://example.com/nostrasia.png"],
             ["summary","Help me get to Nostrasia"]],
     "content":"Nostrasia travel expenses","sig":"77ab01fe…"}]
← ["OK", "f9a02b6c11…", true, ""]

-- Bob's client builds a NIP-57 zap request for the goal --
-- MUST: relays copied from the goal's "relays" tag --
→ kind 9734 zap request: {"kind":9734,"content":"Godspeed!",
     "tags":[["relays","wss://alicerelay.example.com","wss://bobrelay.example.com"],
             ["amount","21000000"],
             ["e","f9a02b6c11…"],
             ["p","a1ice9f2…"]], …}

-- Bob pays the invoice; the lnurl server publishes the receipt --
← ["EVENT", "goalsub", {"kind":9735, "tags":[["e","f9a02b6c11…"],
     ["p","a1ice9f2…"], ["bolt11","lnbc210m…"], ["description","…"]], …}]

-- tally: 21 000 000 / 210 000 000 millisats = 10% funded --

To render the progress bar, a client subscribes on the goal's relays with a filter such as {"kinds":[9735], "#e":["f9a02b6c11…"]}. It sums the receipt amounts. It drops receipts published after closed_at.

6 Version History

NIP-75 has stayed close to its original shape. Notable changes, newest first:

  • 20242024-09Renamed "parameterized replaceable event" to "addressable event" across the text, matching the NIP-01 vocabulary change.
  • 20232023-11Added the optional image and summary tags.
  • 20232023-11JSON reformatting; author lines removed from all NIPs.
  • Origin2023-09Alejandro proposed Zap Goals in PR #757.

Original Proposal - Credits

AuthorAlejandro
First commit2023-09-01 — “NIP-75: Zap Goals (#757)”
Statusdraft - optional
Source75.md on GitHub - full change history

7 See Also

  • NIP-01 — the base event format, tag rules, and storage classes that kind 9041 follows.
  • NIP-57 — the zap flow: zap requests (kind 9734), zap receipts (kind 9735), and the zap beneficiary tag.
  • NIP-23 — long-form posts, a common host for goal tags.
  • NIP-58 — badges, another event type that can carry a funding goal.
  • NIP-53 — live activities; live streams often attach zap goals.