diff options
| -rw-r--r-- | 01.md | 15 | ||||
| -rw-r--r-- | 09.md | 5 | ||||
| -rw-r--r-- | 11.md | 15 | ||||
| -rw-r--r-- | 12.md | 2 | ||||
| -rw-r--r-- | 14.md | 4 | ||||
| -rw-r--r-- | 18.md | 21 | ||||
| -rw-r--r-- | 23.md | 6 | ||||
| -rw-r--r-- | 25.md | 24 | ||||
| -rw-r--r-- | 26.md | 2 | ||||
| -rw-r--r-- | 32.md | 126 | ||||
| -rw-r--r-- | 36.md | 9 | ||||
| -rw-r--r-- | 47.md | 6 | ||||
| -rw-r--r-- | 53.md | 125 | ||||
| -rw-r--r-- | 56.md | 20 | ||||
| -rw-r--r-- | 57.md | 2 | ||||
| -rw-r--r-- | 65.md | 6 | ||||
| -rw-r--r-- | 98.md | 68 | ||||
| -rw-r--r-- | 99.md | 83 | ||||
| -rw-r--r-- | README.md | 40 |
19 files changed, 538 insertions, 41 deletions
| @@ -16,7 +16,7 @@ The only object type that exists is the `event`, which has the following format | |||
| 16 | 16 | ||
| 17 | ```json | 17 | ```json |
| 18 | { | 18 | { |
| 19 | "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data> | 19 | "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>, |
| 20 | "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, | 20 | "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, |
| 21 | "created_at": <unix timestamp in seconds>, | 21 | "created_at": <unix timestamp in seconds>, |
| 22 | "kind": <integer>, | 22 | "kind": <integer>, |
| @@ -55,7 +55,7 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th | |||
| 55 | * `["REQ", <subscription_id>, <filters JSON>...]`, used to request events and subscribe to new updates. | 55 | * `["REQ", <subscription_id>, <filters JSON>...]`, used to request events and subscribe to new updates. |
| 56 | * `["CLOSE", <subscription_id>]`, used to stop previous subscriptions. | 56 | * `["CLOSE", <subscription_id>]`, used to stop previous subscriptions. |
| 57 | 57 | ||
| 58 | `<subscription_id>` is an arbitrary, non-empty string of max length 64 chars, that should be used to represent a subscription. | 58 | `<subscription_id>` is an arbitrary, non-empty string of max length 64 chars, that should be used to represent a subscription. Relays should manage `<subscription_id>`s independently for each WebSocket connection; even if `<subscription_id>`s are the same string, they should be treated as different subscriptions for different connections. |
| 59 | 59 | ||
| 60 | `<filters>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes: | 60 | `<filters>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes: |
| 61 | 61 | ||
| @@ -66,8 +66,8 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th | |||
| 66 | "kinds": <a list of a kind numbers>, | 66 | "kinds": <a list of a kind numbers>, |
| 67 | "#e": <a list of event ids that are referenced in an "e" tag>, | 67 | "#e": <a list of event ids that are referenced in an "e" tag>, |
| 68 | "#p": <a list of pubkeys that are referenced in a "p" tag>, | 68 | "#p": <a list of pubkeys that are referenced in a "p" tag>, |
| 69 | "since": <an integer unix timestamp, events must be newer than this to pass>, | 69 | "since": <an integer unix timestamp in seconds, events must be newer than this to pass>, |
| 70 | "until": <an integer unix timestamp, events must be older than this to pass>, | 70 | "until": <an integer unix timestamp in seconds, events must be older than this to pass>, |
| 71 | "limit": <maximum number of events to be returned in the initial query> | 71 | "limit": <maximum number of events to be returned in the initial query> |
| 72 | } | 72 | } |
| 73 | ``` | 73 | ``` |
| @@ -78,11 +78,13 @@ Filter attributes containing lists (such as `ids`, `kinds`, or `#e`) are JSON ar | |||
| 78 | 78 | ||
| 79 | The `ids` and `authors` lists contain lowercase hexadecimal strings, which may either be an exact 64-character match, or a prefix of the event value. A prefix match is when the filter string is an exact string prefix of the event value. The use of prefixes allows for more compact filters where a large number of values are queried, and can provide some privacy for clients that may not want to disclose the exact authors or events they are searching for. | 79 | The `ids` and `authors` lists contain lowercase hexadecimal strings, which may either be an exact 64-character match, or a prefix of the event value. A prefix match is when the filter string is an exact string prefix of the event value. The use of prefixes allows for more compact filters where a large number of values are queried, and can provide some privacy for clients that may not want to disclose the exact authors or events they are searching for. |
| 80 | 80 | ||
| 81 | The `since` and `until` properties can be used to specify the time range of events returned in the subscription. If a filter includes the `since` property, events with `created_at` greater than or equal to `since` are considered to match the filter. The `until` property is similar except that `created_at` must be less than or equal to `until`. In short, an event matches a filter if `since <= created_at <= until` holds. | ||
| 82 | |||
| 81 | All conditions of a filter that are specified must match for an event for it to pass the filter, i.e., multiple conditions are interpreted as `&&` conditions. | 83 | All conditions of a filter that are specified must match for an event for it to pass the filter, i.e., multiple conditions are interpreted as `&&` conditions. |
| 82 | 84 | ||
| 83 | A `REQ` message may contain multiple filters. In this case, events that match any of the filters are to be returned, i.e., multiple filters are to be interpreted as `||` conditions. | 85 | A `REQ` message may contain multiple filters. In this case, events that match any of the filters are to be returned, i.e., multiple filters are to be interpreted as `||` conditions. |
| 84 | 86 | ||
| 85 | The `limit` property of a filter is only valid for the initial query and can be ignored afterward. When `limit: n` is present it is assumed that the events returned in the initial query will be the latest `n` events. It is safe to return less events than `limit` specifies, but it is expected that relays do not return (much) more events than requested so clients don't get unnecessarily overwhelmed by data. | 87 | The `limit` property of a filter is only valid for the initial query and can be ignored afterward. When `limit: n` is present it is assumed that the events returned in the initial query will be the last `n` events ordered by the `created_at`. It is safe to return less events than `limit` specifies, but it is expected that relays do not return (much) more events than requested so clients don't get unnecessarily overwhelmed by data. |
| 86 | 88 | ||
| 87 | ### From relay to client: sending events and notices | 89 | ### From relay to client: sending events and notices |
| 88 | 90 | ||
| @@ -107,6 +109,7 @@ A relay may choose to treat different message kinds differently, and it may or m | |||
| 107 | ## Other Notes: | 109 | ## Other Notes: |
| 108 | 110 | ||
| 109 | - Clients should not open more than one websocket to each relay. One channel can support an unlimited number of subscriptions, so clients should do that. | 111 | - Clients should not open more than one websocket to each relay. One channel can support an unlimited number of subscriptions, so clients should do that. |
| 110 | - The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](10.md) for a detailed description of "e" and "p" tags. | 112 | - The `tags` array can store a case-sensitive tag name as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](10.md) for a detailed description of "e" and "p" tags. |
| 111 | - The `<recommended relay URL>` item present on the `"e"` and `"p"` tags is an optional (could be set to `""`) URL of a relay the client could attempt to connect to fetch the tagged event or other events from a tagged profile. It MAY be ignored, but it exists to increase censorship resistance and make the spread of relay addresses more seamless across clients. | 113 | - The `<recommended relay URL>` item present on the `"e"` and `"p"` tags is an optional (could be set to `""`) URL of a relay the client could attempt to connect to fetch the tagged event or other events from a tagged profile. It MAY be ignored, but it exists to increase censorship resistance and make the spread of relay addresses more seamless across clients. |
| 112 | - Clients should use the created_at field to judge the age of a metadata event and completely replace older metadata events with newer metadata events regardless of the order in which they arrive. Clients should not merge any filled fields within older metadata events into empty fields of newer metadata events. | 114 | - Clients should use the created_at field to judge the age of a metadata event and completely replace older metadata events with newer metadata events regardless of the order in which they arrive. Clients should not merge any filled fields within older metadata events into empty fields of newer metadata events. |
| 115 | - When a websocket is closed by the relay with a status code 4000 that means the client shouldn't try to connect again. | ||
| @@ -8,7 +8,7 @@ Event Deletion | |||
| 8 | 8 | ||
| 9 | A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted. | 9 | A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted. |
| 10 | 10 | ||
| 11 | Each tag entry must contain an "e" event id intended for deletion. | 11 | Each tag entry must contain an "e" event id and/or NIP-33 `a` tags intended for deletion. |
| 12 | 12 | ||
| 13 | The event's `content` field MAY contain a text note describing the reason for the deletion. | 13 | The event's `content` field MAY contain a text note describing the reason for the deletion. |
| 14 | 14 | ||
| @@ -20,7 +20,8 @@ For example: | |||
| 20 | "pubkey": <32-bytes hex-encoded public key of the event creator>, | 20 | "pubkey": <32-bytes hex-encoded public key of the event creator>, |
| 21 | "tags": [ | 21 | "tags": [ |
| 22 | ["e", "dcd59..464a2"], | 22 | ["e", "dcd59..464a2"], |
| 23 | ["e", "968c5..ad7a4"] | 23 | ["e", "968c5..ad7a4"], |
| 24 | ["a", "<kind>:<pubkey>:<d-identifier>"] | ||
| 24 | ], | 25 | ], |
| 25 | "content": "these posts were published by accident", | 26 | "content": "these posts were published by accident", |
| 26 | ...other fields | 27 | ...other fields |
| @@ -255,6 +255,18 @@ Relays that require payments may want to expose their fee schedules. | |||
| 255 | } | 255 | } |
| 256 | ``` | 256 | ``` |
| 257 | 257 | ||
| 258 | ### Icon ### | ||
| 259 | |||
| 260 | A URL pointing to an image to be used as an icon for the relay. Recommended to be squared in shape. | ||
| 261 | |||
| 262 | ```json | ||
| 263 | { | ||
| 264 | ... | ||
| 265 | "icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg", | ||
| 266 | ... | ||
| 267 | } | ||
| 268 | ``` | ||
| 269 | |||
| 258 | ### Examples ### | 270 | ### Examples ### |
| 259 | As of 2 May 2023 the following `curl` command provided these results. | 271 | As of 2 May 2023 the following `curl` command provided these results. |
| 260 | 272 | ||
| @@ -281,4 +293,5 @@ As of 2 May 2023 the following `curl` command provided these results. | |||
| 281 | "payment_required":true}, | 293 | "payment_required":true}, |
| 282 | "payments_url":"https://eden.nostr.land/invoices", | 294 | "payments_url":"https://eden.nostr.land/invoices", |
| 283 | "fees":{"admission":[{"amount":5000000,"unit":"msats"}], | 295 | "fees":{"admission":[{"amount":5000000,"unit":"msats"}], |
| 284 | "publication":[]}} | 296 | "publication":[]}}, |
| 297 | "icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg" | ||
| @@ -8,7 +8,7 @@ Generic Tag Queries | |||
| 8 | 8 | ||
| 9 | Relays may support subscriptions over arbitrary tags. `NIP-01` requires relays to respond to queries for `e` and `p` tags. This NIP allows any single-letter tag present in an event to be queried. | 9 | Relays may support subscriptions over arbitrary tags. `NIP-01` requires relays to respond to queries for `e` and `p` tags. This NIP allows any single-letter tag present in an event to be queried. |
| 10 | 10 | ||
| 11 | The `<filters>` object described in `NIP-01` is expanded to contain arbitrary keys with a `#` prefix. Any single-letter key in a filter beginning with `#` is a tag query, and MUST have a value of an array of strings. The filter condition matches if the event has a tag with the same name, and there is at least one tag value in common with the filter and event. The tag name is the letter without the `#`, and the tag value is the second element. Subsequent elements are ignored for the purposes of tag queries. | 11 | The `<filters>` object described in `NIP-01` is expanded to contain arbitrary keys with a `#` prefix. Any single-letter key in a filter beginning with `#` is a tag query, and MUST have a value of an array of strings. The filter condition matches if the event has a tag with the same name, and there is at least one tag value in common with the filter and event. The tag name is the letter without the `#`, and the tag value is the second element. Subsequent elements are ignored for the purposes of tag queries. Note that tag names are case-sensitive. |
| 12 | 12 | ||
| 13 | Example Subscription Filter | 13 | Example Subscription Filter |
| 14 | --------------------------- | 14 | --------------------------- |
| @@ -1,8 +1,8 @@ | |||
| 1 | NIP-14 | 1 | NIP-14 |
| 2 | ====== | 2 | ====== |
| 3 | 3 | ||
| 4 | Subject tag in Text events. | 4 | Subject tag in Text events |
| 5 | --------------------------- | 5 | -------------------------- |
| 6 | 6 | ||
| 7 | `draft` `optional` `author:unclebobmartin` | 7 | `draft` `optional` `author:unclebobmartin` |
| 8 | 8 | ||
| @@ -6,11 +6,10 @@ Reposts | |||
| 6 | 6 | ||
| 7 | `draft` `optional` `author:jb55` `author:fiatjaf` `author:arthurfranca` | 7 | `draft` `optional` `author:jb55` `author:fiatjaf` `author:arthurfranca` |
| 8 | 8 | ||
| 9 | A repost is a `kind 6` note that is used to signal to followers | 9 | A repost is a `kind 6` event that is used to signal to followers |
| 10 | that another event is worth reading. | 10 | that a `kind 1` text note is worth reading. |
| 11 | 11 | ||
| 12 | The `content` of a repost event is empty. Optionally, it MAY contain | 12 | The `content` of a repost event is _the stringified JSON of the reposted note_. It MAY also be empty, but that is not recommended. |
| 13 | the stringified JSON of the reposted note event for quick look up. | ||
| 14 | 13 | ||
| 15 | The repost event MUST include an `e` tag with the `id` of the note that is | 14 | The repost event MUST include an `e` tag with the `id` of the note that is |
| 16 | being reposted. That tag MUST include a relay URL as its third entry | 15 | being reposted. That tag MUST include a relay URL as its third entry |
| @@ -21,5 +20,15 @@ reposted. | |||
| 21 | 20 | ||
| 22 | ## Quote Reposts | 21 | ## Quote Reposts |
| 23 | 22 | ||
| 24 | Quote reposts are `kind 1` events with an embedded `e` tag (see [NIP-08](08.md) and [NIP-27](27.md)). | 23 | Quote reposts are `kind 1` events with an embedded `e` tag |
| 25 | Because a quote repost includes an `e` tag, it may show up along replies to the reposted note. | 24 | (see [NIP-08](08.md) and [NIP-27](27.md)). Because a quote repost includes |
| 25 | an `e` tag, it may show up along replies to the reposted note. | ||
| 26 | |||
| 27 | ## Generic Reposts | ||
| 28 | |||
| 29 | Since `kind 6` reposts are reserved for `kind 1` contents, we use `kind 16` | ||
| 30 | as a "generic repost", that can include any kind of event inside other than | ||
| 31 | `kind 1`. | ||
| 32 | |||
| 33 | `kind 16` reposts SHOULD contain a `k` tag with the stringified kind number | ||
| 34 | of the reposted event as its value. | ||
| @@ -12,7 +12,11 @@ This NIP defines `kind:30023` (a parameterized replaceable event according to [N | |||
| 12 | 12 | ||
| 13 | ### Format | 13 | ### Format |
| 14 | 14 | ||
| 15 | The `.content` of these events should be a string text in Markdown syntax. | 15 | The `.content` of these events should be a string text in Markdown syntax. To maximize compatibility and readability between different clients and devices, any client that is creating long form notes: |
| 16 | |||
| 17 | - MUST NOT hard line-break paragraphs of text, such as arbitrary line breaks at 80 column boundaries. | ||
| 18 | |||
| 19 | - MUST NOT support adding HTML to Markdown. | ||
| 16 | 20 | ||
| 17 | ### Metadata | 21 | ### Metadata |
| 18 | 22 | ||
| @@ -18,7 +18,7 @@ downvote or dislike on a post. A client MAY also choose to tally likes against | |||
| 18 | dislikes in a reddit-like system of upvotes and downvotes, or display them as | 18 | dislikes in a reddit-like system of upvotes and downvotes, or display them as |
| 19 | separate tallies. | 19 | separate tallies. |
| 20 | 20 | ||
| 21 | The `content` MAY be an emoji, in this case it MAY be interpreted as a "like" or "dislike", | 21 | The `content` MAY be an emoji, or [NIP-30](30.md) custom emoji in this case it MAY be interpreted as a "like" or "dislike", |
| 22 | or the client MAY display this emoji reaction on the post. | 22 | or the client MAY display this emoji reaction on the post. |
| 23 | 23 | ||
| 24 | Tags | 24 | Tags |
| @@ -47,3 +47,25 @@ func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> Nost | |||
| 47 | ev.sign(privkey: privkey) | 47 | ev.sign(privkey: privkey) |
| 48 | return ev | 48 | return ev |
| 49 | } | 49 | } |
| 50 | ``` | ||
| 51 | |||
| 52 | Custom Emoji Reaction | ||
| 53 | --------------------- | ||
| 54 | |||
| 55 | The client may specify a custom emoji ([NIP-30](30.md)) `:shortcode:` in the | ||
| 56 | reaction content. The client should refer to the emoji tag and render the | ||
| 57 | content as an emoji if shortcode is specified. | ||
| 58 | |||
| 59 | ```json | ||
| 60 | { | ||
| 61 | "kind": 7, | ||
| 62 | "content": ":soapbox:", | ||
| 63 | "tags": [ | ||
| 64 | ["emoji", "soapbox", "https://gleasonator.com/emoji/Gleasonator/soapbox.png"] | ||
| 65 | ], | ||
| 66 | "pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6", | ||
| 67 | "created_at": 1682790000 | ||
| 68 | } | ||
| 69 | ``` | ||
| 70 | |||
| 71 | The content can be set only one `:shortcode:`. And emoji tag should be one. | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | NIP: 26 | 1 | NIP-26 |
| 2 | ======= | 2 | ======= |
| 3 | 3 | ||
| 4 | Delegated Event Signing | 4 | Delegated Event Signing |
| @@ -0,0 +1,126 @@ | |||
| 1 | NIP-32 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | Labeling | ||
| 5 | --------- | ||
| 6 | |||
| 7 | `draft` `optional` `author:staab` `author:gruruya` `author:s3x-jay` | ||
| 8 | |||
| 9 | A label is a `kind 1985` event that is used to label other entities. This supports a number of use cases, from distributed moderation and content recommendations to reviews and ratings. | ||
| 10 | |||
| 11 | Label Target | ||
| 12 | ---- | ||
| 13 | |||
| 14 | The label event MUST include one or more tags representing the object or objects being | ||
| 15 | labeled: `e`, `p`, `a`, `r`, or `t` tags. This allows for labeling of events, people, relays, | ||
| 16 | or topics respectively. As with NIP-01, a relay hint SHOULD be included when using `e` and | ||
| 17 | `p` tags. | ||
| 18 | |||
| 19 | Label Tag | ||
| 20 | ---- | ||
| 21 | |||
| 22 | This NIP introduces a new tag `l` which denotes a label, and a new `L` tag which denotes a label namespace. | ||
| 23 | A label MUST include a mark matching an `L` tag. `L` tags refer to a tag type within nostr, or a nomenclature | ||
| 24 | external to nostr defined either formally or by convention. Any string can be a namespace, but publishers SHOULD | ||
| 25 | ensure they are unambiguous by using a well-defined namespace (such as an ISO standard) or reverse domain name notation. | ||
| 26 | |||
| 27 | Namespaces starting with `#` indicate that the label target should be associated with the label's value. | ||
| 28 | This is a way of attaching standard nostr tags to events, pubkeys, relays, urls, etc. | ||
| 29 | |||
| 30 | Some examples: | ||
| 31 | |||
| 32 | - `["l", "footstr", "#t"]` - the publisher thinks the given entity should have the `footstr` topic applied. | ||
| 33 | - `["l", "<pubkey>", "#p"]` - the publisher thinks the given entity is related to `<pubkey>` | ||
| 34 | - `["l", "IT-MI", "ISO-3166-2"]` - Milano, Italy using ISO 3166-2. | ||
| 35 | - `["l", "VI-hum", "com.example.ontology"]` - Violence toward a human being as defined by ontology.example.com. | ||
| 36 | |||
| 37 | `L` tags containing the label namespaces MUST be included in order to support searching by | ||
| 38 | namespace rather than by a specific tag. The special `ugc` ("user generated content") namespace | ||
| 39 | MAY be used when the label content is provided by an end user. | ||
| 40 | |||
| 41 | `l` and `L` tags MAY be added to other event kinds to support self-reporting. For events | ||
| 42 | with a kind other than 1985, labels refer to the event itself. | ||
| 43 | |||
| 44 | Label Annotations | ||
| 45 | ----- | ||
| 46 | |||
| 47 | A label tag MAY include a 4th positional element detailing extra metadata about the label in question. This string | ||
| 48 | should be a json-encoded object. Any key MAY be used, but the following are recommended: | ||
| 49 | |||
| 50 | - `quality` may have a value of 0 to 1. This allows for an absolute, granular scale that can be represented in any way (5 stars, color scale, etc). | ||
| 51 | - `confidence` may have a value of 0 to 1. This indicates the certainty which the author has about their rating. | ||
| 52 | - `context` may be an array of urls (including NIP-21 urls) indicating other context that should be considered when interpreting labels. | ||
| 53 | |||
| 54 | Content | ||
| 55 | ------- | ||
| 56 | |||
| 57 | Labels should be short, meaningful strings. Longer discussions, such as for a review, or an | ||
| 58 | explanation of why something was labeled the way it was, should go in the event's `content` field. | ||
| 59 | |||
| 60 | Example events | ||
| 61 | -------------- | ||
| 62 | |||
| 63 | A suggestion that multiple pubkeys be associated with the `permies` topic. | ||
| 64 | |||
| 65 | ```json | ||
| 66 | { | ||
| 67 | "kind": 1985, | ||
| 68 | "tags": [ | ||
| 69 | ["L", "#t"], | ||
| 70 | ["l", "permies", "#t"], | ||
| 71 | ["p", <pubkey1>, <relay_url>], | ||
| 72 | ["p", <pubkey2>, <relay_url>] | ||
| 73 | ], | ||
| 74 | "content": "", | ||
| 75 | ... | ||
| 76 | } | ||
| 77 | ``` | ||
| 78 | |||
| 79 | A review of a relay. | ||
| 80 | |||
| 81 | ```json | ||
| 82 | { | ||
| 83 | "kind": 1985, | ||
| 84 | "tags": [ | ||
| 85 | ["L", "com.example.ontology"], | ||
| 86 | ["l", "relay/review", "com.example.ontology", "{\"quality\": 0.1}"], | ||
| 87 | ["r", <relay_url>] | ||
| 88 | ], | ||
| 89 | "content": "This relay is full of mean people.", | ||
| 90 | ... | ||
| 91 | } | ||
| 92 | ``` | ||
| 93 | |||
| 94 | Publishers can self-label by adding `l` tags to their own non-1985 events. | ||
| 95 | |||
| 96 | ```json | ||
| 97 | { | ||
| 98 | "kind": 1, | ||
| 99 | "tags": [ | ||
| 100 | ["L", "com.example.ontology"], | ||
| 101 | ["l", "IL-frd", "com.example.ontology"] | ||
| 102 | ], | ||
| 103 | "content": "Send me 100 sats and I'll send you 200 back", | ||
| 104 | ... | ||
| 105 | } | ||
| 106 | ``` | ||
| 107 | |||
| 108 | Other Notes | ||
| 109 | ----------- | ||
| 110 | |||
| 111 | When using this NIP to bulk-label many targets at once, events may be deleted and a replacement | ||
| 112 | may be published. We have opted not to use parameterizable/replaceable events for this due to the | ||
| 113 | complexity in coming up with a standard `d` tag. In order to avoid ambiguity when querying, | ||
| 114 | publishers SHOULD limit labeling events to a single namespace. | ||
| 115 | |||
| 116 | Before creating a vocabulary, explore how your use case may have already been designed and | ||
| 117 | imitate that design if possible. Reverse domain name notation is encouraged to avoid | ||
| 118 | namespace clashes, but for the sake of interoperability all namespaces should be | ||
| 119 | considered open for public use, and not proprietary. In other words, if there is a | ||
| 120 | namespace that fits your use case, use it even if it points to someone else's domain name. | ||
| 121 | |||
| 122 | Vocabularies MAY choose to fully qualify all labels within a namespace (for example, | ||
| 123 | `["l", "com.example.vocabulary:my-label"]`. This may be preferred when defining more | ||
| 124 | formal vocabularies that should not be confused with another namespace when querying | ||
| 125 | without an `L` tag. For these vocabularies, all labels SHOULD include the namespace | ||
| 126 | (rather than mixing qualified and unqualified labels). | ||
| @@ -9,12 +9,15 @@ Sensitive Content / Content Warning | |||
| 9 | The `content-warning` tag enables users to specify if the event's content needs to be approved by readers to be shown. | 9 | The `content-warning` tag enables users to specify if the event's content needs to be approved by readers to be shown. |
| 10 | Clients can hide the content until the user acts on it. | 10 | Clients can hide the content until the user acts on it. |
| 11 | 11 | ||
| 12 | `l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) with the `content-warning` or other namespace to support | ||
| 13 | further qualification and querying. | ||
| 14 | |||
| 12 | #### Spec | 15 | #### Spec |
| 13 | 16 | ||
| 14 | ``` | 17 | ``` |
| 15 | tag: content-warning | 18 | tag: content-warning |
| 16 | options: | 19 | options: |
| 17 | - [reason]: optional | 20 | - [reason]: optional |
| 18 | ``` | 21 | ``` |
| 19 | 22 | ||
| 20 | #### Example | 23 | #### Example |
| @@ -26,6 +29,10 @@ options: | |||
| 26 | "kind": 1, | 29 | "kind": 1, |
| 27 | "tags": [ | 30 | "tags": [ |
| 28 | ["t", "hastag"], | 31 | ["t", "hastag"], |
| 32 | ["L", "content-warning"], | ||
| 33 | ["l", "reason", "content-warning"], | ||
| 34 | ["L", "social.nos.ontology"], | ||
| 35 | ["l", "NS-nud", "social.nos.ontology"], | ||
| 29 | ["content-warning", "reason"] /* reason is optional */ | 36 | ["content-warning", "reason"] /* reason is optional */ |
| 30 | ], | 37 | ], |
| 31 | "content": "sensitive content with #hastag\n", | 38 | "content": "sensitive content with #hastag\n", |
| @@ -33,7 +33,7 @@ There are three event kinds: | |||
| 33 | - `NIP-47 response`: 23195 | 33 | - `NIP-47 response`: 23195 |
| 34 | 34 | ||
| 35 | The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which commands it supports. The content should be | 35 | The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which commands it supports. The content should be |
| 36 | a plaintext string with the supported commands, space-seperated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs. | 36 | a plaintext string with the supported commands, space-separated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs. |
| 37 | 37 | ||
| 38 | Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. | 38 | Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. |
| 39 | 39 | ||
| @@ -64,8 +64,8 @@ Response: | |||
| 64 | ``` | 64 | ``` |
| 65 | 65 | ||
| 66 | The `result_type` field MUST contain the name of the method that this event is responding to. | 66 | The `result_type` field MUST contain the name of the method that this event is responding to. |
| 67 | The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not succesful. | 67 | The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not successful. |
| 68 | If the command was succesful, the `error` field must be null. | 68 | If the command was successful, the `error` field must be null. |
| 69 | 69 | ||
| 70 | ### Error codes | 70 | ### Error codes |
| 71 | - `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. | 71 | - `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. |
| @@ -0,0 +1,125 @@ | |||
| 1 | NIP-53 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | Live Activities | ||
| 5 | --------------- | ||
| 6 | |||
| 7 | `draft` `optional` `author:vitorpamplona` `author:v0l` | ||
| 8 | |||
| 9 | ## Abstract | ||
| 10 | |||
| 11 | Service providers want to offer live activities to the Nostr network in such a way that participants can easily logged and queried by clients. This NIP describes a general framework to advertise the involvement of pubkeys in such live activities. | ||
| 12 | |||
| 13 | # Live Event | ||
| 14 | |||
| 15 | A special event with `kind:30311` "Live Event" is defined as a [NIP-33: Parameterized Replaceable Events](33.md) of public `p` tags. Each `p` tag SHOULD have a **displayable** marker name for the current role (e.g. `Host`, `Speaker`, `Participant`) of the user in the event and the relay information MAY be empty. This event will be constantly updated as participants join and leave the activity. | ||
| 16 | |||
| 17 | For example: | ||
| 18 | |||
| 19 | ```js | ||
| 20 | { | ||
| 21 | "kind": 30311, | ||
| 22 | "tags": [ | ||
| 23 | ["d", "<unique identifier>"], | ||
| 24 | ["title", "<name of the event>"], | ||
| 25 | ["summary", "<description>"], | ||
| 26 | ["image", "<preview image url>"], | ||
| 27 | ["t", "hashtag"] | ||
| 28 | ["streaming", "<url>"], | ||
| 29 | ["recording", "<url>"], // used to place the edited video once the activity is over | ||
| 30 | ["starts", "<unix timestamp in seconds>"], | ||
| 31 | ["ends", "<unix timestamp in seconds>"], | ||
| 32 | ["status", "<planned, live, ended>"], | ||
| 33 | ["current_participants", "<number>"], | ||
| 34 | ["total_participants", "<number>"], | ||
| 35 | ["p", "91cf9..4e5ca", "wss://provider1.com/", "Host", "<proof>"], | ||
| 36 | ["p", "14aeb..8dad4", "wss://provider2.com/nostr", "Speaker"], | ||
| 37 | ["p", "612ae..e610f", "ws://provider3.com/ws", "Participant"], | ||
| 38 | ["relays", "wss://one.com", "wss://two.com", ...] | ||
| 39 | ], | ||
| 40 | "content": "", | ||
| 41 | ...other fields | ||
| 42 | } | ||
| 43 | ``` | ||
| 44 | |||
| 45 | A distinct `d` tag should be used for each activity. All other tags are optional. | ||
| 46 | |||
| 47 | Providers SHOULD keep the participant list small (e.g. under 1000 users) and, when limits are reached, Providers SHOULD select which participants get named in the event. Clients should not expect a comprehensive list. Once the activity ends, the event can be deleted or updated to summarize the activity and provide async content (e.g. recording of the event). | ||
| 48 | |||
| 49 | Clients are expected to subscribe to `kind:30311` events in general or for given follow lists and statuses. Clients MAY display participants' roles in activities as well as access points to join the activity. | ||
| 50 | |||
| 51 | Live Activity management clients are expected to constantly update `kind:30311` during the event. Clients MAY choose to consider `status=live` events after 1hr without any update as `ended`. The `starts` and `ends` timestamp SHOULD be updated when the status changes to and from `live` | ||
| 52 | |||
| 53 | The activity MUST be linked to using the NIP-19 naddr code along with the "a" tag (see [NIP-33](33.md) and [NIP-19](19.md)). | ||
| 54 | |||
| 55 | ## Proof of Agreement to Participate | ||
| 56 | |||
| 57 | Event owners can add proof as the 5th term in each `p` tag to clarify the participant's agreement in joining the event. The proof is a signed SHA256 of the complete `a` Tag of the event (`kind:pubkey:dTag`) by each `p`'s private key, encoded in hex. | ||
| 58 | |||
| 59 | Clients MAY only display participants if the proof is available or MAY display participants as "invited" if the proof is not available. | ||
| 60 | |||
| 61 | This feature is important to avoid malicious event owners adding large account holders to the event, without their knowledge, to lure their followers into the malicious owner's trap. | ||
| 62 | |||
| 63 | # Live Chat Message | ||
| 64 | |||
| 65 | Event `kind:1311` is live chat's channel message. Clients MUST include the `a` tag of the activity with a `root` marker. Other Kind-1 tags such as `reply` and `mention` can also be used. | ||
| 66 | |||
| 67 | ```js | ||
| 68 | { | ||
| 69 | "id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>", | ||
| 70 | "pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>", | ||
| 71 | "created_at": "<Unix timestamp in seconds>", | ||
| 72 | "kind": 1311, | ||
| 73 | "tags": [ | ||
| 74 | ["a", "30311:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>", "root"], | ||
| 75 | ], | ||
| 76 | "content": "Zaps to live streams is beautiful." | ||
| 77 | } | ||
| 78 | ``` | ||
| 79 | |||
| 80 | # Use Cases | ||
| 81 | |||
| 82 | Common use cases include meeting rooms/workshops, watch-together activities, or event spaces, such as [live.snort.social](https://live.snort.social) and [nostrnests.com](https://nostrnests.com). | ||
| 83 | |||
| 84 | # Example | ||
| 85 | |||
| 86 | Live Streaming | ||
| 87 | |||
| 88 | ```json | ||
| 89 | { | ||
| 90 | "id": "57f28dbc264990e2c61e80a883862f7c114019804208b14da0bff81371e484d2", | ||
| 91 | "pubkey": "1597246ac22f7d1375041054f2a4986bd971d8d196d7997e48973263ac9879ec", | ||
| 92 | "created_at": 1687182672, | ||
| 93 | "kind": 30311, | ||
| 94 | "tags": [ | ||
| 95 | ["d", "demo-cf-stream"], | ||
| 96 | ["title", "Adult Swim Metalocalypse"], | ||
| 97 | ["summary", "Live stream from IPTV-ORG collection"], | ||
| 98 | ["streaming", "https://adultswim-vodlive.cdn.turner.com/live/metalocalypse/stream.m3u8"], | ||
| 99 | ["starts", "1687182672"] | ||
| 100 | ["status", "live"], | ||
| 101 | ["t", "animation"], | ||
| 102 | ["t", "iptv"], | ||
| 103 | ["image", "https://i.imgur.com/CaKq6Mt.png"] | ||
| 104 | ], | ||
| 105 | "content": "", | ||
| 106 | "sig": "5bc7a60f5688effa5287244a24768cbe0dcd854436090abc3bef172f7f5db1410af4277508dbafc4f70a754a891c90ce3b966a7bc47e7c1eb71ff57640f3d389" | ||
| 107 | } | ||
| 108 | ``` | ||
| 109 | |||
| 110 | Live Streaming chat message | ||
| 111 | |||
| 112 | ```json | ||
| 113 | { | ||
| 114 | "id": "97aa81798ee6c5637f7b21a411f89e10244e195aa91cb341bf49f718e36c8188", | ||
| 115 | "pubkey": "3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24", | ||
| 116 | "created_at": 1687286726, | ||
| 117 | "kind": 1311, | ||
| 118 | "tags": [ | ||
| 119 | ["a", "30311:1597246ac22f7d1375041054f2a4986bd971d8d196d7997e48973263ac9879ec:demo-cf-stream", "", "root"] | ||
| 120 | ], | ||
| 121 | "content": "Zaps to live streams is beautiful.", | ||
| 122 | "sig": "997f62ddfc0827c121043074d50cfce7a528e978c575722748629a4137c45b75bdbc84170bedc723ef0a5a4c3daebf1fef2e93f5e2ddb98e5d685d022c30b622" | ||
| 123 | } | ||
| 124 | ```` | ||
| 125 | |||
| @@ -10,7 +10,7 @@ Reporting | |||
| 10 | A report is a `kind 1984` note that is used to report other notes for spam, | 10 | A report is a `kind 1984` note that is used to report other notes for spam, |
| 11 | illegal and explicit content. | 11 | illegal and explicit content. |
| 12 | 12 | ||
| 13 | The content MAY contain additional information submitted by the entity | 13 | The `content` MAY contain additional information submitted by the entity |
| 14 | reporting the content. | 14 | reporting the content. |
| 15 | 15 | ||
| 16 | Tags | 16 | Tags |
| @@ -32,6 +32,9 @@ being reported, which consists of the following report types: | |||
| 32 | 32 | ||
| 33 | Some report tags only make sense for profile reports, such as `impersonation` | 33 | Some report tags only make sense for profile reports, such as `impersonation` |
| 34 | 34 | ||
| 35 | `l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) to support | ||
| 36 | further qualification and querying. | ||
| 37 | |||
| 35 | Example events | 38 | Example events |
| 36 | -------------- | 39 | -------------- |
| 37 | 40 | ||
| @@ -39,7 +42,9 @@ Example events | |||
| 39 | { | 42 | { |
| 40 | "kind": 1984, | 43 | "kind": 1984, |
| 41 | "tags": [ | 44 | "tags": [ |
| 42 | [ "p", <pubkey>, "nudity"] | 45 | ["p", <pubkey>, "nudity"], |
| 46 | ["L", "social.nos.ontology"], | ||
| 47 | ["l", "NS-nud", "social.nos.ontology"] | ||
| 43 | ], | 48 | ], |
| 44 | "content": "", | 49 | "content": "", |
| 45 | ... | 50 | ... |
| @@ -48,8 +53,8 @@ Example events | |||
| 48 | { | 53 | { |
| 49 | "kind": 1984, | 54 | "kind": 1984, |
| 50 | "tags": [ | 55 | "tags": [ |
| 51 | [ "e", <eventId>, "illegal"], | 56 | ["e", <eventId>, "illegal"], |
| 52 | [ "p", <pubkey>] | 57 | ["p", <pubkey>] |
| 53 | ], | 58 | ], |
| 54 | "content": "He's insulting the king!", | 59 | "content": "He's insulting the king!", |
| 55 | ... | 60 | ... |
| @@ -58,10 +63,9 @@ Example events | |||
| 58 | { | 63 | { |
| 59 | "kind": 1984, | 64 | "kind": 1984, |
| 60 | "tags": [ | 65 | "tags": [ |
| 61 | [ "p", <impersonator pubkey>, "impersonation"], | 66 | ["p", <impersonator pubkey>, "impersonation"] |
| 62 | [ "p", <victim pubkey>] | ||
| 63 | ], | 67 | ], |
| 64 | "content": "Profile is imitating #[1]", | 68 | "content": "Profile is impersonating nostr:<victim bech32 pubkey>", |
| 65 | ... | 69 | ... |
| 66 | } | 70 | } |
| 67 | ``` | 71 | ``` |
| @@ -70,7 +74,7 @@ Client behavior | |||
| 70 | --------------- | 74 | --------------- |
| 71 | 75 | ||
| 72 | Clients can use reports from friends to make moderation decisions if they | 76 | Clients can use reports from friends to make moderation decisions if they |
| 73 | choose to. For instance, if 3+ of your friends report a profile as explicit, | 77 | choose to. For instance, if 3+ of your friends report a profile for `nudity`, |
| 74 | clients can have an option to automatically blur photos from said account. | 78 | clients can have an option to automatically blur photos from said account. |
| 75 | 79 | ||
| 76 | 80 | ||
| @@ -126,7 +126,7 @@ When receiving a payment, the following steps are executed: | |||
| 126 | 126 | ||
| 127 | The following should be true of the `zap receipt` event: | 127 | The following should be true of the `zap receipt` event: |
| 128 | 128 | ||
| 129 | - The content SHOULD be empty. | 129 | - The `content` SHOULD be empty. |
| 130 | - The `created_at` date SHOULD be set to the invoice `paid_at` date for idempotency. | 130 | - The `created_at` date SHOULD be set to the invoice `paid_at` date for idempotency. |
| 131 | - `tags` MUST include the `p` tag AND optional `e` tag from the `zap request`. | 131 | - `tags` MUST include the `p` tag AND optional `e` tag from the `zap request`. |
| 132 | - The `zap receipt` MUST have a `bolt11` tag containing the description hash bolt11 invoice. | 132 | - The `zap receipt` MUST have a `bolt11` tag containing the description hash bolt11 invoice. |
| @@ -10,7 +10,7 @@ A special replaceable event meaning "Relay List Metadata" is defined as an event | |||
| 10 | 10 | ||
| 11 | The primary purpose of this relay list is to advertise to others, not for configuring one's client. | 11 | The primary purpose of this relay list is to advertise to others, not for configuring one's client. |
| 12 | 12 | ||
| 13 | The content is not used and SHOULD be an empty string. | 13 | The `content` is not used and SHOULD be an empty string. |
| 14 | 14 | ||
| 15 | The `r` tags can have a second parameter as either `read` or `write`. If it is omitted, it means the author uses the relay for both purposes. | 15 | The `r` tags can have a second parameter as either `read` or `write`. If it is omitted, it means the author uses the relay for both purposes. |
| 16 | 16 | ||
| @@ -53,12 +53,12 @@ Authors may post events outside of the feed that they wish their followers to fo | |||
| 53 | It is suggested that relays allow any user to write their own kind `10002` event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because | 53 | It is suggested that relays allow any user to write their own kind `10002` event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because |
| 54 | 54 | ||
| 55 | - finding where someone posts is rather important | 55 | - finding where someone posts is rather important |
| 56 | - these events do not have content that needs management | 56 | - these events do not have `content` that needs management |
| 57 | - relays only need to store one replaceable event per pubkey to offer this service | 57 | - relays only need to store one replaceable event per pubkey to offer this service |
| 58 | 58 | ||
| 59 | ### Why not in kind `0` Metadata | 59 | ### Why not in kind `0` Metadata |
| 60 | 60 | ||
| 61 | Even though this is user related metadata, it is a separate event from kind `0` in order to keep it small (as it should be widely spread) and to not have content that may require moderation by relay operators so that it is more acceptable to relays. | 61 | Even though this is user related metadata, it is a separate event from kind `0` in order to keep it small (as it should be widely spread) and to not have `content` that may require moderation by relay operators so that it is more acceptable to relays. |
| 62 | 62 | ||
| 63 | ### Example | 63 | ### Example |
| 64 | 64 | ||
| @@ -0,0 +1,68 @@ | |||
| 1 | NIP-98 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | HTTP Auth | ||
| 5 | ------------------------- | ||
| 6 | |||
| 7 | `draft` `optional` `author:kieran` `author:melvincarvalho` | ||
| 8 | |||
| 9 | This NIP defines an ephemerial event used to authorize requests to HTTP servers using nostr events. | ||
| 10 | |||
| 11 | This is useful for HTTP services which are build for Nostr and deal with Nostr user accounts. | ||
| 12 | |||
| 13 | ## Nostr event | ||
| 14 | |||
| 15 | A `kind 27235` (In reference to [RFC 7235](https://www.rfc-editor.org/rfc/rfc7235)) event is used. | ||
| 16 | |||
| 17 | The `content` SHOULD be empty. | ||
| 18 | |||
| 19 | The following tags are defined as REQUIRED. | ||
| 20 | |||
| 21 | * `u` - absolute URL | ||
| 22 | * `method` - HTTP Request Method | ||
| 23 | |||
| 24 | Example event: | ||
| 25 | ```json | ||
| 26 | { | ||
| 27 | "id": "fe964e758903360f28d8424d092da8494ed207cba823110be3a57dfe4b578734", | ||
| 28 | "pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", | ||
| 29 | "content": "", | ||
| 30 | "kind": 27235, | ||
| 31 | "created_at": 1682327852, | ||
| 32 | "tags": [ | ||
| 33 | [ | ||
| 34 | "u", | ||
| 35 | "https://api.snort.social/api/v1/n5sp/list" | ||
| 36 | ], | ||
| 37 | [ | ||
| 38 | "method", | ||
| 39 | "GET" | ||
| 40 | ] | ||
| 41 | ], | ||
| 42 | "sig": "5ed9d8ec958bc854f997bdc24ac337d005af372324747efe4a00e24f4c30437ff4dd8308684bed467d9d6be3e5a517bb43b1732cc7d33949a3aaf86705c22184" | ||
| 43 | } | ||
| 44 | ``` | ||
| 45 | |||
| 46 | Servers MUST perform the following checks in order to validate the event: | ||
| 47 | 1. The `kind` MUST be `27235`. | ||
| 48 | 2. The `created_at` MUST be within a reasonable time window (suggestion 60 seconds). | ||
| 49 | 3. The `u` tag MUST be exactly the same as the absolute request URL (including query parameters). | ||
| 50 | 4. The `method` tag MUST be the same HTTP method used for the requested resource. | ||
| 51 | |||
| 52 | When the request contains a body (as in POST/PUT/PATCH methods) clients SHOULD include a SHA256 hash of the request body in a `payload` tag as hex (`["payload", "<sha256-hex>"]`), servers MAY check this to validate that the requested payload is authorized. | ||
| 53 | |||
| 54 | If one of the checks was to fail the server SHOULD respond with a 401 Unauthorized response code. | ||
| 55 | |||
| 56 | All other checks which server MAY do are OPTIONAL, and implementation specific. | ||
| 57 | |||
| 58 | ## Request Flow | ||
| 59 | |||
| 60 | Using the `Authorization` header, the `kind 27235` event MUST be `base64` encoded and use the Authorization scheme `Nostr` | ||
| 61 | |||
| 62 | Example HTTP Authorization header: | ||
| 63 | ``` | ||
| 64 | Authorization: Nostr eyJpZCI6ImZlOTY0ZTc1ODkwMzM2MGYyOGQ4NDI0ZDA5MmRhODQ5NGVkMjA3Y2JhODIzMTEwYmUzYTU3ZGZlNGI1Nzg3MzQiLCJwdWJrZXkiOiI2M2ZlNjMxOGRjNTg1ODNjZmUxNjgxMGY4NmRkMDllMThiZmQ3NmFhYmMyNGEwMDgxY2UyODU2ZjMzMDUwNGVkIiwiY29udGVudCI6IiIsImtpbmQiOjI3MjM1LCJjcmVhdGVkX2F0IjoxNjgyMzI3ODUyLCJ0YWdzIjpbWyJ1cmwiLCJodHRwczovL2FwaS5zbm9ydC5zb2NpYWwvYXBpL3YxL241c3AvbGlzdCJdLFsibWV0aG9kIiwiR0VUIl1dLCJzaWciOiI1ZWQ5ZDhlYzk1OGJjODU0Zjk5N2JkYzI0YWMzMzdkMDA1YWYzNzIzMjQ3NDdlZmU0YTAwZTI0ZjRjMzA0MzdmZjRkZDgzMDg2ODRiZWQ0NjdkOWQ2YmUzZTVhNTE3YmI0M2IxNzMyY2M3ZDMzOTQ5YTNhYWY4NjcwNWMyMjE4NCJ9 | ||
| 65 | ``` | ||
| 66 | |||
| 67 | ## Reference Implementations | ||
| 68 | - C# ASP.NET `AuthenticationHandler` [NostrAuth.cs](https://gist.github.com/v0l/74346ae530896115bfe2504c8cd018d3) \ No newline at end of file | ||
| @@ -0,0 +1,83 @@ | |||
| 1 | # NIP-99 | ||
| 2 | |||
| 3 | ## Classified Listings | ||
| 4 | |||
| 5 | `draft` `optional` `author:erskingardner` | ||
| 6 | |||
| 7 | This NIP defines `kind:30402`: a parameterized replaceable event to describe classified listings that list any arbitrary product, service, or other thing for sale or offer and includes enough structured metadata to make them useful. | ||
| 8 | |||
| 9 | The category of classifieds includes a very broad range of physical goods, services, work opportunities, rentals, free giveaways, personals, etc. and is distinct from the more strictly structured marketplaces defined in [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) that often sell many units of specific products through very specific channels. | ||
| 10 | |||
| 11 | The structure of these events is very similar to [NIP-23](https://github.com/nostr-protocol/nips/blob/master/23.md) long-form content events. | ||
| 12 | |||
| 13 | ### Draft / Inactive Listings | ||
| 14 | |||
| 15 | `kind:30403` has the same structure as `kind:30402` and is used to save draft or inactive classified listings. | ||
| 16 | |||
| 17 | ### Content | ||
| 18 | |||
| 19 | The `.content` field should be a description of what is being offered and by whom. These events should be a string in Markdown syntax. | ||
| 20 | |||
| 21 | ### Author | ||
| 22 | |||
| 23 | The `.pubkey` field of these events are treated as the party creating the listing. | ||
| 24 | |||
| 25 | ### Metadata | ||
| 26 | |||
| 27 | - For "tags"/"hashtags" (i.e. categories or keywords of relevance for the listing) the `"t"` event tag should be used, as per [NIP-12](https://github.com/nostr-protocol/nips/blob/master/12.md). | ||
| 28 | - For images, whether included in the markdown content or not, clients SHOULD use `image` tags as described in [NIP-58](https://github.com/nostr-protocol/nips/blob/master/58.md). This allows clients to display images in carousel format more easily. | ||
| 29 | |||
| 30 | The following tags, used for structured metadata, are standardized and SHOULD be included. Other tags may be added as necessary. | ||
| 31 | |||
| 32 | - `"title"`, a title for the listing | ||
| 33 | - `"summary"`, for short tagline or summary for the listing | ||
| 34 | - `"published_at"`, for the timestamp (in unix seconds – converted to string) of the first time the listing was published. | ||
| 35 | - `"location"`, for the location. | ||
| 36 | - `"price"`, for the price of the thing being listed. This is an array in the format `[ "price", "<number>", "<currency>", "<frequency>" ]`. | ||
| 37 | - `"price"` is the name of the tag | ||
| 38 | - `"<number>"` is the amount in numeric format (but included in the tag as a string) | ||
| 39 | - `"<currency>"` is the currency unit in 3-character ISO 4217 format or ISO 4217-like currency code (e.g. `"btc"`, `"eth"`). | ||
| 40 | - `"<frequency>"` is optional and can be used to describe recurring payments. SHOULD be in noun format (hour, day, week, month, year, etc.) | ||
| 41 | |||
| 42 | #### `price` examples | ||
| 43 | |||
| 44 | - $50 one-time payment `["price", "50", "USD"]` | ||
| 45 | - €15 per month `["price", "15", "EUR", "month"]` | ||
| 46 | - £50,000 per year `["price", "50000", "GBP", "year"]` | ||
| 47 | |||
| 48 | Other standard tags that might be useful. | ||
| 49 | |||
| 50 | - `"g"`, a geohash for more precise location | ||
| 51 | |||
| 52 | ## Example Event | ||
| 53 | |||
| 54 | ```json | ||
| 55 | { | ||
| 56 | "kind": 30402, | ||
| 57 | "created_at": 1675642635, | ||
| 58 | // Markdown content | ||
| 59 | "content": "Lorem [ipsum][nostr:nevent1qqst8cujky046negxgwwm5ynqwn53t8aqjr6afd8g59nfqwxpdhylpcpzamhxue69uhhyetvv9ujuetcv9khqmr99e3k7mg8arnc9] dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nRead more at nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu.", | ||
| 60 | "tags": [ | ||
| 61 | ["d", "lorem-ipsum"], | ||
| 62 | ["title", "Lorem Ipsum"], | ||
| 63 | ["published_at", "1296962229"], | ||
| 64 | ["t", "electronics"], | ||
| 65 | ["image", "https://url.to.img", "256x256"], | ||
| 66 | ["summary", "More lorem ipsum that is a little more than the title"], | ||
| 67 | ["location", "NYC"], | ||
| 68 | ["price", "100", "USD"], | ||
| 69 | [ | ||
| 70 | "e", | ||
| 71 | "b3e392b11f5d4f28321cedd09303a748acfd0487aea5a7450b3481c60b6e4f87", | ||
| 72 | "wss://relay.example.com" | ||
| 73 | ], | ||
| 74 | [ | ||
| 75 | "a", | ||
| 76 | "30023:a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919:ipsum", | ||
| 77 | "wss://relay.nostr.org" | ||
| 78 | ] | ||
| 79 | ], | ||
| 80 | "pubkey": "...", | ||
| 81 | "id": "..." | ||
| 82 | } | ||
| 83 | ``` | ||
| @@ -32,13 +32,13 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 32 | - [NIP-11: Relay Information Document](11.md) | 32 | - [NIP-11: Relay Information Document](11.md) |
| 33 | - [NIP-12: Generic Tag Queries](12.md) | 33 | - [NIP-12: Generic Tag Queries](12.md) |
| 34 | - [NIP-13: Proof of Work](13.md) | 34 | - [NIP-13: Proof of Work](13.md) |
| 35 | - [NIP-14: Subject tag in text events.](14.md) | 35 | - [NIP-14: Subject tag in text events](14.md) |
| 36 | - [NIP-15: Nostr Marketplace (for resilient marketplaces)](15.md) | 36 | - [NIP-15: Nostr Marketplace (for resilient marketplaces)](15.md) |
| 37 | - [NIP-16: Event Treatment](16.md) | 37 | - [NIP-16: Event Treatment](16.md) |
| 38 | - [NIP-18: Reposts](18.md) | 38 | - [NIP-18: Reposts](18.md) |
| 39 | - [NIP-19: bech32-encoded entities](19.md) | 39 | - [NIP-19: bech32-encoded entities](19.md) |
| 40 | - [NIP-20: Command Results](20.md) | 40 | - [NIP-20: Command Results](20.md) |
| 41 | - [NIP-21: `nostr:` URL scheme](21.md) | 41 | - [NIP-21: `nostr:` URI scheme](21.md) |
| 42 | - [NIP-22: Event `created_at` Limits](22.md) | 42 | - [NIP-22: Event `created_at` Limits](22.md) |
| 43 | - [NIP-23: Long-form Content](23.md) | 43 | - [NIP-23: Long-form Content](23.md) |
| 44 | - [NIP-25: Reactions](25.md) | 44 | - [NIP-25: Reactions](25.md) |
| @@ -47,6 +47,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 47 | - [NIP-28: Public Chat](28.md) | 47 | - [NIP-28: Public Chat](28.md) |
| 48 | - [NIP-30: Custom Emoji](30.md) | 48 | - [NIP-30: Custom Emoji](30.md) |
| 49 | - [NIP-31: Dealing with Unknown Events](31.md) | 49 | - [NIP-31: Dealing with Unknown Events](31.md) |
| 50 | - [NIP-32: Labeling](32.md) | ||
| 50 | - [NIP-33: Parameterized Replaceable Events](33.md) | 51 | - [NIP-33: Parameterized Replaceable Events](33.md) |
| 51 | - [NIP-36: Sensitive Content](36.md) | 52 | - [NIP-36: Sensitive Content](36.md) |
| 52 | - [NIP-39: External Identities in Profiles](39.md) | 53 | - [NIP-39: External Identities in Profiles](39.md) |
| @@ -57,6 +58,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 57 | - [NIP-47: Wallet Connect](47.md) | 58 | - [NIP-47: Wallet Connect](47.md) |
| 58 | - [NIP-50: Keywords filter](50.md) | 59 | - [NIP-50: Keywords filter](50.md) |
| 59 | - [NIP-51: Lists](51.md) | 60 | - [NIP-51: Lists](51.md) |
| 61 | - [NIP-53: Live Activities](53.md) | ||
| 60 | - [NIP-56: Reporting](56.md) | 62 | - [NIP-56: Reporting](56.md) |
| 61 | - [NIP-57: Lightning Zaps](57.md) | 63 | - [NIP-57: Lightning Zaps](57.md) |
| 62 | - [NIP-58: Badges](58.md) | 64 | - [NIP-58: Badges](58.md) |
| @@ -64,6 +66,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 64 | - [NIP-78: Application-specific data](78.md) | 66 | - [NIP-78: Application-specific data](78.md) |
| 65 | - [NIP-89: Recommended Application Handlers](89.md) | 67 | - [NIP-89: Recommended Application Handlers](89.md) |
| 66 | - [NIP-94: File Metadata](94.md) | 68 | - [NIP-94: File Metadata](94.md) |
| 69 | - [NIP-98: HTTP Auth](98.md) | ||
| 70 | - [NIP-99: Classified Listings](99.md) | ||
| 67 | 71 | ||
| 68 | ## Event Kinds | 72 | ## Event Kinds |
| 69 | 73 | ||
| @@ -75,16 +79,19 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 75 | | `3` | Contacts | [2](02.md) | | 79 | | `3` | Contacts | [2](02.md) | |
| 76 | | `4` | Encrypted Direct Messages | [4](04.md) | | 80 | | `4` | Encrypted Direct Messages | [4](04.md) | |
| 77 | | `5` | Event Deletion | [9](09.md) | | 81 | | `5` | Event Deletion | [9](09.md) | |
| 78 | | `6` | Reposts | [18](18.md) | | 82 | | `6` | Repost | [18](18.md) | |
| 79 | | `7` | Reaction | [25](25.md) | | 83 | | `7` | Reaction | [25](25.md) | |
| 80 | | `8` | Badge Award | [58](58.md) | | 84 | | `8` | Badge Award | [58](58.md) | |
| 85 | | `16` | Generic Repost | [18](18.md) | | ||
| 81 | | `40` | Channel Creation | [28](28.md) | | 86 | | `40` | Channel Creation | [28](28.md) | |
| 82 | | `41` | Channel Metadata | [28](28.md) | | 87 | | `41` | Channel Metadata | [28](28.md) | |
| 83 | | `42` | Channel Message | [28](28.md) | | 88 | | `42` | Channel Message | [28](28.md) | |
| 84 | | `43` | Channel Hide Message | [28](28.md) | | 89 | | `43` | Channel Hide Message | [28](28.md) | |
| 85 | | `44` | Channel Mute User | [28](28.md) | | 90 | | `44` | Channel Mute User | [28](28.md) | |
| 86 | | `1063` | File Metadata | [94](94.md) | | 91 | | `1063` | File Metadata | [94](94.md) | |
| 92 | | `1311` | Live Chat Message | [53](53.md) | | ||
| 87 | | `1984` | Reporting | [56](56.md) | | 93 | | `1984` | Reporting | [56](56.md) | |
| 94 | | `1985` | Label | [32](32.md) | | ||
| 88 | | `9734` | Zap Request | [57](57.md) | | 95 | | `9734` | Zap Request | [57](57.md) | |
| 89 | | `9735` | Zap | [57](57.md) | | 96 | | `9735` | Zap | [57](57.md) | |
| 90 | | `10000` | Mute List | [51](51.md) | | 97 | | `10000` | Mute List | [51](51.md) | |
| @@ -95,6 +102,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 95 | | `23194` | Wallet Request | [47](47.md) | | 102 | | `23194` | Wallet Request | [47](47.md) | |
| 96 | | `23195` | Wallet Response | [47](47.md) | | 103 | | `23195` | Wallet Response | [47](47.md) | |
| 97 | | `24133` | Nostr Connect | [46](46.md) | | 104 | | `24133` | Nostr Connect | [46](46.md) | |
| 105 | | `27235` | HTTP Auth | [98](98.md) | | ||
| 98 | | `30000` | Categorized People List | [51](51.md) | | 106 | | `30000` | Categorized People List | [51](51.md) | |
| 99 | | `30001` | Categorized Bookmark List | [51](51.md) | | 107 | | `30001` | Categorized Bookmark List | [51](51.md) | |
| 100 | | `30008` | Profile Badges | [58](58.md) | | 108 | | `30008` | Profile Badges | [58](58.md) | |
| @@ -102,7 +110,11 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 102 | | `30017` | Create or update a stall | [15](15.md) | | 110 | | `30017` | Create or update a stall | [15](15.md) | |
| 103 | | `30018` | Create or update a product | [15](15.md) | | 111 | | `30018` | Create or update a product | [15](15.md) | |
| 104 | | `30023` | Long-form Content | [23](23.md) | | 112 | | `30023` | Long-form Content | [23](23.md) | |
| 113 | | `30024` | Draft Long-form Content | [23](23.md) | | ||
| 105 | | `30078` | Application-specific Data | [78](78.md) | | 114 | | `30078` | Application-specific Data | [78](78.md) | |
| 115 | | `30311` | Live Event | [53](53.md) | | ||
| 116 | | `30402` | Classified Listing | [99](99.md) | | ||
| 117 | | `30403` | Draft Classified Listing | [99](99.md) | | ||
| 106 | | `31989` | Handler recommendation | [89](89.md) | | 118 | | `31989` | Handler recommendation | [89](89.md) | |
| 107 | | `31990` | Handler information | [89](89.md) | | 119 | | `31990` | Handler information | [89](89.md) | |
| 108 | 120 | ||
| @@ -152,6 +164,9 @@ When experimenting with kinds, keep in mind the classification introduced by [NI | |||
| 152 | | `e` | event id (hex) | relay URL, marker | [1](01.md), [10](10.md) | | 164 | | `e` | event id (hex) | relay URL, marker | [1](01.md), [10](10.md) | |
| 153 | | `g` | geohash | -- | [12](12.md) | | 165 | | `g` | geohash | -- | [12](12.md) | |
| 154 | | `i` | identity | proof | [39](39.md) | | 166 | | `i` | identity | proof | [39](39.md) | |
| 167 | | `k` | kind number (string) | -- | [18](18.md) | | ||
| 168 | | `l` | label, label namespace | annotations | [32](32.md) | | ||
| 169 | | `L` | label namespace | -- | [32](32.md) | | ||
| 155 | | `p` | pubkey (hex) | relay URL | [1](01.md) | | 170 | | `p` | pubkey (hex) | relay URL | [1](01.md) | |
| 156 | | `r` | a reference (URL, etc) | -- | [12](12.md) | | 171 | | `r` | a reference (URL, etc) | -- | [12](12.md) | |
| 157 | | `t` | hashtag | -- | [12](12.md) | | 172 | | `t` | hashtag | -- | [12](12.md) | |
| @@ -162,13 +177,15 @@ When experimenting with kinds, keep in mind the classification introduced by [NI | |||
| 162 | | `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) | | 177 | | `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) | |
| 163 | | `description` | badge description | -- | [58](58.md) | | 178 | | `description` | badge description | -- | [58](58.md) | |
| 164 | | `description` | invoice description | -- | [57](57.md) | | 179 | | `description` | invoice description | -- | [57](57.md) | |
| 165 | | `emoji` | shortcode | image URL | [30](30.md) | | 180 | | `emoji` | shortcode, image URL | -- | [30](30.md) | |
| 166 | | `expiration` | unix timestamp (string) | -- | [40](40.md) | | 181 | | `expiration` | unix timestamp (string) | -- | [40](40.md) | |
| 167 | | `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) | | 182 | | `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) | |
| 168 | | `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) | | 183 | | `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) | |
| 184 | | `location` | location string | -- | [99](99.md) | | ||
| 169 | | `name` | badge name | -- | [58](58.md) | | 185 | | `name` | badge name | -- | [58](58.md) | |
| 170 | | `nonce` | random | -- | [13](13.md) | | 186 | | `nonce` | random | -- | [13](13.md) | |
| 171 | | `preimage` | hash of `bolt11` invoice | -- | [57](57.md) | | 187 | | `preimage` | hash of `bolt11` invoice | -- | [57](57.md) | |
| 188 | | `price` | price | currency, frequency | [99](99.md) | | ||
| 172 | | `published_at` | unix timestamp (string) | -- | [23](23.md) | | 189 | | `published_at` | unix timestamp (string) | -- | [23](23.md) | |
| 173 | | `relay` | relay url | -- | [42](42.md) | | 190 | | `relay` | relay url | -- | [42](42.md) | |
| 174 | | `relays` | relay list | -- | [57](57.md) | | 191 | | `relays` | relay list | -- | [57](57.md) | |
| @@ -186,6 +203,21 @@ When experimenting with kinds, keep in mind the classification introduced by [NI | |||
| 186 | 4. There should be no more than one way of doing the same thing. | 203 | 4. There should be no more than one way of doing the same thing. |
| 187 | 5. Other rules will be made up when necessary. | 204 | 5. Other rules will be made up when necessary. |
| 188 | 205 | ||
| 206 | ## Mailing Lists | ||
| 207 | |||
| 208 | The nostr ecosystem is getting large with many different organizations, relays | ||
| 209 | and clients. Following the nips repo on github is becoming more difficult and | ||
| 210 | noisy. To coordinate on protocol development outside of github, there are | ||
| 211 | mailing lists where you can work on NIPs before submitting them here: | ||
| 212 | |||
| 213 | * [w3c nostr community group][w3-nostr] - [public-nostr@w3.org][mailto-w3] - requires signup | ||
| 214 | * [nostr-protocol google group][nostr-google-group] - [nostr-protocol@googlegroups.com][mailto-google] - no signup required | ||
| 215 | |||
| 216 | [w3-nostr]: https://www.w3.org/community/nostr/ | ||
| 217 | [mailto-w3]: mailto:public-nostr@w3.org | ||
| 218 | [nostr-google-group]: https://groups.google.com/g/nostr-protocol | ||
| 219 | [mailto-google]: mailto:nostr-protocol@googlegroups.com | ||
| 220 | |||
| 189 | ## License | 221 | ## License |
| 190 | 222 | ||
| 191 | All NIPs are public domain. | 223 | All NIPs are public domain. |