diff options
| -rw-r--r-- | 01.md | 16 | ||||
| -rw-r--r-- | 02.md | 20 | ||||
| -rw-r--r-- | 07.md | 1 | ||||
| -rw-r--r-- | 09.md | 2 | ||||
| -rw-r--r-- | 10.md | 2 | ||||
| -rw-r--r-- | 11.md | 11 | ||||
| -rw-r--r-- | 15.md | 2 | ||||
| -rw-r--r-- | 22.md | 45 | ||||
| -rw-r--r-- | 42.md | 71 | ||||
| -rw-r--r-- | 45.md | 11 | ||||
| -rw-r--r-- | 47.md | 2 | ||||
| -rw-r--r-- | 51.md | 189 | ||||
| -rw-r--r-- | 53.md | 2 | ||||
| -rw-r--r-- | 57.md | 4 | ||||
| -rw-r--r-- | 58.md | 2 | ||||
| -rw-r--r-- | 75.md | 4 | ||||
| -rw-r--r-- | 89.md | 8 | ||||
| -rw-r--r-- | 90.md | 2 | ||||
| -rw-r--r-- | README.md | 144 |
19 files changed, 256 insertions, 282 deletions
| @@ -96,10 +96,6 @@ These are just conventions and relay implementations may differ. | |||
| 96 | 96 | ||
| 97 | Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc. | 97 | Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc. |
| 98 | 98 | ||
| 99 | ### Meaning of WebSocket status codes | ||
| 100 | |||
| 101 | - When a websocket is closed by the relay with a status code `4000` that means the client shouldn't try to connect again. | ||
| 102 | |||
| 103 | ### From client to relay: sending events and creating subscriptions | 99 | ### From client to relay: sending events and creating subscriptions |
| 104 | 100 | ||
| 105 | Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns: | 101 | Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns: |
| @@ -145,19 +141,25 @@ Relays can send 4 types of messages, which must also be JSON arrays, according t | |||
| 145 | * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients. | 141 | * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients. |
| 146 | * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message. | 142 | * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message. |
| 147 | * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time. | 143 | * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time. |
| 144 | * `["CLOSED", <subscription_id>, <message>]`, used to indicate that a subscription was ended on the server side. | ||
| 148 | * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients. | 145 | * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients. |
| 149 | 146 | ||
| 150 | This NIP defines no rules for how `NOTICE` messages should be sent or treated. | 147 | This NIP defines no rules for how `NOTICE` messages should be sent or treated. |
| 151 | 148 | ||
| 152 | - `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above). | 149 | - `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above). |
| 153 | - `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. The standardized machine-readable prefixes are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits. Some examples: | 150 | - `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. Some examples: |
| 154 | |||
| 155 | * `["OK", "b1a649ebe8...", true, ""]` | 151 | * `["OK", "b1a649ebe8...", true, ""]` |
| 156 | * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]` | 152 | * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]` |
| 157 | * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]` | 153 | * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]` |
| 158 | * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]` | 154 | * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]` |
| 159 | * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]` | 155 | * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]` |
| 160 | * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]` | 156 | * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]` |
| 161 | * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time. Is your system clock in sync?"]` | 157 | * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time"]` |
| 162 | * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]` | 158 | * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]` |
| 163 | * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]` | 159 | * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]` |
| 160 | - `CLOSED` messages MUST be sent in response to a `REQ` when the relay refuses to fulfill it. It can also be sent when a relay decides to kill a subscription on its side before a client has disconnected or sent a `CLOSE`. This message uses the same pattern of `OK` messages with the machine-readable prefix and human-readable message. Some examples: | ||
| 161 | * `["CLOSED", "sub1", "duplicate: sub1 already opened"]` | ||
| 162 | * `["CLOSED", "sub1", "unsupported: filter contains unknown elements"]` | ||
| 163 | * `["CLOSED", "sub1", "error: could not connect to the database"]` | ||
| 164 | * `["CLOSED", "sub1", "error: shutting down idle subscription"]` | ||
| 165 | - The standardized machine-readable prefixes for `OK` and `CLOSED` are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits. | ||
| @@ -1,12 +1,12 @@ | |||
| 1 | NIP-02 | 1 | NIP-02 |
| 2 | ====== | 2 | ====== |
| 3 | 3 | ||
| 4 | Contact List and Petnames | 4 | Follow List |
| 5 | ------------------------- | 5 | ----------- |
| 6 | 6 | ||
| 7 | `final` `optional` | 7 | `final` `optional` |
| 8 | 8 | ||
| 9 | A special event with kind `3`, meaning "contact list" is defined as having a list of `p` tags, one for each of the followed/known profiles one is following. | 9 | A special event with kind `3`, meaning "follow list" is defined as having a list of `p` tags, one for each of the followed/known profiles one is following. |
| 10 | 10 | ||
| 11 | Each tag entry should contain the key for the profile, a relay URL where events from that key can be found (can be set to an empty string if not needed), and a local name (or "petname") for that profile (can also be set to an empty string or not provided), i.e., `["p", <32-bytes hex key>, <main relay URL>, <petname>]`. The `content` can be anything and should be ignored. | 11 | Each tag entry should contain the key for the profile, a relay URL where events from that key can be found (can be set to an empty string if not needed), and a local name (or "petname") for that profile (can also be set to an empty string or not provided), i.e., `["p", <32-bytes hex key>, <main relay URL>, <petname>]`. The `content` can be anything and should be ignored. |
| 12 | 12 | ||
| @@ -25,27 +25,27 @@ For example: | |||
| 25 | } | 25 | } |
| 26 | ``` | 26 | ``` |
| 27 | 27 | ||
| 28 | Every new contact list that gets published overwrites the past ones, so it should contain all entries. Relays and clients SHOULD delete past contact lists as soon as they receive a new one. | 28 | Every new following list that gets published overwrites the past ones, so it should contain all entries. Relays and clients SHOULD delete past following lists as soon as they receive a new one. |
| 29 | 29 | ||
| 30 | ## Uses | 30 | ## Uses |
| 31 | 31 | ||
| 32 | ### Contact list backup | 32 | ### Follow list backup |
| 33 | 33 | ||
| 34 | If one believes a relay will store their events for sufficient time, they can use this kind-3 event to backup their following list and recover on a different device. | 34 | If one believes a relay will store their events for sufficient time, they can use this kind-3 event to backup their following list and recover on a different device. |
| 35 | 35 | ||
| 36 | ### Profile discovery and context augmentation | 36 | ### Profile discovery and context augmentation |
| 37 | 37 | ||
| 38 | A client may rely on the kind-3 event to display a list of followed people by profiles one is browsing; make lists of suggestions on who to follow based on the contact lists of other people one might be following or browsing; or show the data in other contexts. | 38 | A client may rely on the kind-3 event to display a list of followed people by profiles one is browsing; make lists of suggestions on who to follow based on the follow lists of other people one might be following or browsing; or show the data in other contexts. |
| 39 | 39 | ||
| 40 | ### Relay sharing | 40 | ### Relay sharing |
| 41 | 41 | ||
| 42 | A client may publish a full list of contacts with good relays for each of their contacts so other clients may use these to update their internal relay lists if needed, increasing censorship-resistance. | 42 | A client may publish a follow list with good relays for each of their follows so other clients may use these to update their internal relay lists if needed, increasing censorship-resistance. |
| 43 | 43 | ||
| 44 | ### Petname scheme | 44 | ### Petname scheme |
| 45 | 45 | ||
| 46 | The data from these contact lists can be used by clients to construct local ["petname"](http://www.skyhunter.com/marcs/petnames/IntroPetNames.html) tables derived from other people's contact lists. This alleviates the need for global human-readable names. For example: | 46 | The data from these follow lists can be used by clients to construct local ["petname"](http://www.skyhunter.com/marcs/petnames/IntroPetNames.html) tables derived from other people's follow lists. This alleviates the need for global human-readable names. For example: |
| 47 | 47 | ||
| 48 | A user has an internal contact list that says | 48 | A user has an internal follow list that says |
| 49 | 49 | ||
| 50 | ```json | 50 | ```json |
| 51 | [ | 51 | [ |
| @@ -53,7 +53,7 @@ A user has an internal contact list that says | |||
| 53 | ] | 53 | ] |
| 54 | ``` | 54 | ``` |
| 55 | 55 | ||
| 56 | And receives two contact lists, one from `21df6d143fb96c2ec9d63726bf9edc71` that says | 56 | And receives two follow lists, one from `21df6d143fb96c2ec9d63726bf9edc71` that says |
| 57 | 57 | ||
| 58 | ```json | 58 | ```json |
| 59 | [ | 59 | [ |
| @@ -36,3 +36,4 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext | |||
| 36 | - [Spring Browser](https://spring.site) (Android) | 36 | - [Spring Browser](https://spring.site) (Android) |
| 37 | - [nodestr](https://github.com/lightning-digital-entertainment/nodestr) (NodeJS polyfill) | 37 | - [nodestr](https://github.com/lightning-digital-entertainment/nodestr) (NodeJS polyfill) |
| 38 | - [Nostore](https://apps.apple.com/us/app/nostore/id1666553677) (Safari on iOS/MacOS) | 38 | - [Nostore](https://apps.apple.com/us/app/nostore/id1666553677) (Safari on iOS/MacOS) |
| 39 | - [OneKey](https://onekey.so/) (Android, IOS, Chrome and derivatives) | ||
| @@ -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 and/or NIP-33 `a` tags intended for deletion. | 11 | Each tag entry must contain an "e" event id and/or `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 | ||
| @@ -33,7 +33,7 @@ Where: | |||
| 33 | 33 | ||
| 34 | * Many "e" tags: `["e", <root-id>]` `["e", <mention-id>]`, ..., `["e", <reply-id>]`<br> | 34 | * Many "e" tags: `["e", <root-id>]` `["e", <mention-id>]`, ..., `["e", <reply-id>]`<br> |
| 35 | There may be any number of `<mention-ids>`. These are the ids of events which may, or may not be in the reply chain. | 35 | There may be any number of `<mention-ids>`. These are the ids of events which may, or may not be in the reply chain. |
| 36 | They are citings from this event. `root-id` and `reply-id` are as above. | 36 | They are citing from this event. `root-id` and `reply-id` are as above. |
| 37 | 37 | ||
| 38 | >This scheme is deprecated because it creates ambiguities that are difficult, or impossible to resolve when an event references another but is not a reply. | 38 | >This scheme is deprecated because it creates ambiguities that are difficult, or impossible to resolve when an event references another but is not a reply. |
| 39 | 39 | ||
| @@ -79,6 +79,7 @@ are rejected or fail immediately. | |||
| 79 | "min_pow_difficulty": 30, | 79 | "min_pow_difficulty": 30, |
| 80 | "auth_required": true, | 80 | "auth_required": true, |
| 81 | "payment_required": true, | 81 | "payment_required": true, |
| 82 | "restricted_writes": true, | ||
| 82 | "created_at_lower_limit": 31536000, | 83 | "created_at_lower_limit": 31536000, |
| 83 | "created_at_upper_limit": 3 | 84 | "created_at_upper_limit": 3 |
| 84 | }, | 85 | }, |
| @@ -124,9 +125,15 @@ Even if set to False, authentication may be required for specific actions. | |||
| 124 | 125 | ||
| 125 | - `payment_required`: this relay requires payment before a new connection may perform any action. | 126 | - `payment_required`: this relay requires payment before a new connection may perform any action. |
| 126 | 127 | ||
| 127 | - `created_at_lower_limit`: 'created_at' lower limit as defined in [NIP-22](22.md) | 128 | - `restricted_writes`: this relay requires some kind of condition to be fulfilled in order to |
| 129 | accept events (not necessarily, but including `payment_required` and `min_pow_difficulty`). | ||
| 130 | This should only be set to `true` when users are expected to know the relay policy before trying | ||
| 131 | to write to it -- like belonging to a special pubkey-based whitelist or writing only events of | ||
| 132 | a specific niche kind or content. Normal anti-spam heuristics, for example, do not qualify. | ||
| 128 | 133 | ||
| 129 | - `created_at_upper_limit`: 'created_at' upper limit as defined in [NIP-22](22.md) | 134 | - `created_at_lower_limit`: 'created_at' lower limit |
| 135 | |||
| 136 | - `created_at_upper_limit`: 'created_at' upper limit | ||
| 130 | 137 | ||
| 131 | ### Event Retention | 138 | ### Event Retention |
| 132 | 139 | ||
| @@ -108,7 +108,7 @@ Fields that are not self-explanatory: | |||
| 108 | ``` | 108 | ``` |
| 109 | 109 | ||
| 110 | Fields that are not self-explanatory: | 110 | Fields that are not self-explanatory: |
| 111 | - `quantity` can be null in the case of items with unlimited abailability, like digital items, or services | 111 | - `quantity` can be null in the case of items with unlimited availability, like digital items, or services |
| 112 | - `specs`: | 112 | - `specs`: |
| 113 | - an optional array of key pair values. It allows for the Customer UI to present product specifications in a structure mode. It also allows comparison between products | 113 | - an optional array of key pair values. It allows for the Customer UI to present product specifications in a structure mode. It also allows comparison between products |
| 114 | - eg: `[["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]` | 114 | - eg: `[["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]` |
| @@ -1,45 +0,0 @@ | |||
| 1 | NIP-22 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | Event `created_at` Limits | ||
| 5 | ------------------------- | ||
| 6 | |||
| 7 | `draft` `optional` | ||
| 8 | |||
| 9 | Relays may define both upper and lower limits within which they will consider an event's `created_at` to be acceptable. Both the upper and lower limits MUST be unix timestamps in seconds as defined in [NIP-01](01.md). | ||
| 10 | |||
| 11 | If a relay supports this NIP, the relay SHOULD send the client an `OK` result saying the event was not stored for the `created_at` timestamp not being within the permitted limits. | ||
| 12 | |||
| 13 | Client Behavior | ||
| 14 | --------------- | ||
| 15 | |||
| 16 | Clients SHOULD use the [NIP-11](11.md) `supported_nips` field to learn if a relay uses event `created_at` time limits as defined by this NIP. | ||
| 17 | |||
| 18 | Motivation | ||
| 19 | ---------- | ||
| 20 | |||
| 21 | This NIP formalizes restrictions on event timestamps as accepted by a relay and allows clients to be aware of relays that have these restrictions. | ||
| 22 | |||
| 23 | The event `created_at` field is just a unix timestamp and can be set to a time in the past or future. Relays accept and share events dated to 20 years ago or 50,000 years in the future. This NIP aims to define a way for relays that do not want to store events with *any* timestamp to set their own restrictions. | ||
| 24 | |||
| 25 | _Replaceable events_ can behave rather unexpectedly if the user wrote them - or tried to write them - with a wrong system clock. Persisting an update with a backdated system now would result in the update not getting persisted without a notification and if they did the last update with a forward dated system, they will again fail to do another update with the now correct time. | ||
| 26 | |||
| 27 | A wide adoption of this NIP could create a better user experience as it would decrease the amount of events that appear wildly out of order or even from impossible dates in the distant past or future. | ||
| 28 | |||
| 29 | Keep in mind that there is a use case where a user migrates their old posts onto a new relay. If a relay rejects events that were not recently created, it cannot serve this use case. | ||
| 30 | |||
| 31 | |||
| 32 | Python (pseudocode) Example | ||
| 33 | --------------------------- | ||
| 34 | |||
| 35 | ```python | ||
| 36 | import time | ||
| 37 | |||
| 38 | TIME = int(time.time()) | ||
| 39 | LOWER_LIMIT = TIME - (60 * 60 * 24) # Define lower limit as 1 day into the past | ||
| 40 | UPPER_LIMIT = TIME + (60 * 15) # Define upper limit as 15 minutes into the future | ||
| 41 | |||
| 42 | if event.created_at not in range(LOWER_LIMIT, UPPER_LIMIT): | ||
| 43 | ws.send('["OK", event.id, False, "invalid: the event created_at field is out of the acceptable range (-24h, +15min) for this relay"]') | ||
| 44 | ``` | ||
| 45 | Note: These are just example limits, the relay operator can choose whatever limits they want. | ||
| @@ -12,32 +12,31 @@ This NIP defines a way for clients to authenticate to relays by signing an ephem | |||
| 12 | 12 | ||
| 13 | A relay may want to require clients to authenticate to access restricted resources. For example, | 13 | A relay may want to require clients to authenticate to access restricted resources. For example, |
| 14 | 14 | ||
| 15 | - A relay may request payment or other forms of whitelisting to publish events -- this can naïvely be achieved by limiting publication | 15 | - A relay may request payment or other forms of whitelisting to publish events -- this can naïvely be achieved by limiting publication to events signed by the whitelisted key, but with this NIP they may choose to accept any events as long as they are published from an authenticated user; |
| 16 | to events signed by the whitelisted key, but with this NIP they may choose to accept any events as long as they are published from an | 16 | - A relay may limit access to `kind: 4` DMs to only the parties involved in the chat exchange, and for that it may require authentication before clients can query for that kind. |
| 17 | authenticated user; | ||
| 18 | - A relay may limit access to `kind: 4` DMs to only the parties involved in the chat exchange, and for that it may require authentication | ||
| 19 | before clients can query for that kind. | ||
| 20 | - A relay may limit subscriptions of any kind to paying users or users whitelisted through any other means, and require authentication. | 17 | - A relay may limit subscriptions of any kind to paying users or users whitelisted through any other means, and require authentication. |
| 21 | 18 | ||
| 22 | ## Definitions | 19 | ## Definitions |
| 23 | 20 | ||
| 24 | This NIP defines a new message, `AUTH`, which relays can send when they support authentication and clients can send to relays when they want | 21 | ### New client-relay protocol messages |
| 25 | to authenticate. When sent by relays, the message is of the following form: | 22 | |
| 23 | This NIP defines a new message, `AUTH`, which relays CAN send when they support authentication and clients can send to relays when they want to authenticate. When sent by relays the message has the following form: | ||
| 26 | 24 | ||
| 27 | ```json | 25 | ```json |
| 28 | ["AUTH", <challenge-string>] | 26 | ["AUTH", <challenge-string>] |
| 29 | ``` | 27 | ``` |
| 30 | 28 | ||
| 31 | And, when sent by clients, of the following form: | 29 | And, when sent by clients, the following form: |
| 32 | 30 | ||
| 33 | ```json | 31 | ```json |
| 34 | ["AUTH", <signed-event-json>] | 32 | ["AUTH", <signed-event-json>] |
| 35 | ``` | 33 | ``` |
| 36 | 34 | ||
| 37 | The signed event is an ephemeral event not meant to be published or queried, it must be of `kind: 22242` and it should have at least two tags, | 35 | `AUTH` messages sent by clients MUST be answered with an `OK` message, like any `EVENT` message. |
| 38 | one for the relay URL and one for the challenge string as received from the relay. | 36 | |
| 39 | Relays MUST exclude `kind: 22242` events from being broadcasted to any client. | 37 | ### Canonical authentication event |
| 40 | `created_at` should be the current time. Example: | 38 | |
| 39 | The signed event is an ephemeral event not meant to be published or queried, it must be of `kind: 22242` and it should have at least two tags, one for the relay URL and one for the challenge string as received from the relay. Relays MUST exclude `kind: 22242` events from being broadcasted to any client. `created_at` should be the current time. Example: | ||
| 41 | 40 | ||
| 42 | ```json | 41 | ```json |
| 43 | { | 42 | { |
| @@ -50,27 +49,49 @@ Relays MUST exclude `kind: 22242` events from being broadcasted to any client. | |||
| 50 | } | 49 | } |
| 51 | ``` | 50 | ``` |
| 52 | 51 | ||
| 52 | ### `OK` and `CLOSED` machine-readable prefixes | ||
| 53 | |||
| 54 | This NIP defines two new prefixes that can be used in `OK` (in response to event writes by clients) and `CLOSED` (in response to rejected subscriptions by clients): | ||
| 55 | |||
| 56 | - `"auth-required: "` - for when a client has not performed `AUTH` and the relay requires that to fulfill the query or write the event. | ||
| 57 | - `"restricted: "` - for when a client has already performed `AUTH` but the key used to perform it is still not allowed by the relay or is exceeding its authorization. | ||
| 58 | |||
| 53 | ## Protocol flow | 59 | ## Protocol flow |
| 54 | 60 | ||
| 55 | At any moment the relay may send an `AUTH` message to the client containing a challenge. After receiving that the client may decide to | 61 | At any moment the relay may send an `AUTH` message to the client containing a challenge. The challenge is valid for the duration of the connection or until another challenge is sent by the relay. The client MAY decide to send its `AUTH` event at any point and the authenticated session is valid afterwards for the duration of the connection. |
| 56 | authenticate itself or not. The challenge is expected to be valid for the duration of the connection or until a next challenge is sent by | ||
| 57 | the relay. | ||
| 58 | 62 | ||
| 59 | The client may send an auth message right before performing an action for which it knows authentication will be required -- for example, right | 63 | ### `auth-required` in response to a `REQ` message |
| 60 | before requesting `kind: 4` chat messages --, or it may do right on connection start or at some other moment it deems best. The authentication | ||
| 61 | is expected to last for the duration of the WebSocket connection. | ||
| 62 | 64 | ||
| 63 | Upon receiving a message from an unauthenticated user it can't fulfill without authentication, a relay may choose to notify the client. For | 65 | Given that a relay is likely to require clients to perform authentication only for certain jobs, like answering a `REQ` or accepting an `EVENT` write, these are some expected common flows: |
| 64 | that it can use a `NOTICE` or `OK` message with a standard prefix `"restricted: "` that is readable both by humans and machines, for example: | ||
| 65 | 66 | ||
| 66 | ```json | 67 | ``` |
| 67 | ["NOTICE", "restricted: we can't serve DMs to unauthenticated users, does your client implement NIP-42?"] | 68 | relay: ["AUTH", "<challenge>"] |
| 69 | client: ["REQ", "sub_1", {"kinds": [4]}] | ||
| 70 | relay: ["CLOSED", "sub_1", "auth-required: we can't serve DMs to unauthenticated users"] | ||
| 71 | client: ["AUTH", {"id": "abcdef...", ...}] | ||
| 72 | relay: ["OK", "abcdef...", true, ""] | ||
| 73 | client: ["REQ", "sub_1", {"kinds": [4]}] | ||
| 74 | relay: ["EVENT", "sub_1", {...}] | ||
| 75 | relay: ["EVENT", "sub_1", {...}] | ||
| 76 | relay: ["EVENT", "sub_1", {...}] | ||
| 77 | relay: ["EVENT", "sub_1", {...}] | ||
| 78 | ... | ||
| 68 | ``` | 79 | ``` |
| 69 | 80 | ||
| 70 | or it can return an `OK` message noting the reason an event was not written using the same prefix: | 81 | In this case, the `AUTH` message from the relay could be sent right as the client connects or it can be sent immediately before the `CLOSED` is sent. The only requirement is that _the client must have a stored challenge associated with that relay_ so it can act upon that in response to the `auth-required` `CLOSED` message. |
| 71 | 82 | ||
| 72 | ```json | 83 | ### `auth-required` in response to an `EVENT` message |
| 73 | ["OK", <event-id>, false, "restricted: we do not accept events from unauthenticated users, please sign up at https://example.com/"] | 84 | |
| 85 | The same flow is valid for when a client wants to write an `EVENT` to the relay, except now the relay sends back an `OK` message instead of a `CLOSED` message: | ||
| 86 | |||
| 87 | ``` | ||
| 88 | relay: ["AUTH", "<challenge>"] | ||
| 89 | client: ["EVENT", {"id": "012345...", ...}] | ||
| 90 | relay: ["OK", "012345...", false, "auth-required: we only accept events from registered users"] | ||
| 91 | client: ["AUTH", {"id": "abcdef...", ...}] | ||
| 92 | relay: ["OK", "abcdef...", true, ""] | ||
| 93 | client: ["EVENT", {"id": "012345...", ...}] | ||
| 94 | relay: ["OK", "012345...", true, ""] | ||
| 74 | ``` | 95 | ``` |
| 75 | 96 | ||
| 76 | ## Signed Event Verification | 97 | ## Signed Event Verification |
| @@ -27,7 +27,9 @@ In case a relay uses probabilistic counts, it MAY indicate it in the response wi | |||
| 27 | ["COUNT", <subscription_id>, {"count": <integer>}] | 27 | ["COUNT", <subscription_id>, {"count": <integer>}] |
| 28 | ``` | 28 | ``` |
| 29 | 29 | ||
| 30 | ## Examples: | 30 | Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST return a `CLOSED` message. |
| 31 | |||
| 32 | ## Examples | ||
| 31 | 33 | ||
| 32 | ### Followers count | 34 | ### Followers count |
| 33 | 35 | ||
| @@ -49,3 +51,10 @@ In case a relay uses probabilistic counts, it MAY indicate it in the response wi | |||
| 49 | ["COUNT", <subscription_id>, {"kinds": [1]}] | 51 | ["COUNT", <subscription_id>, {"kinds": [1]}] |
| 50 | ["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}] | 52 | ["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}] |
| 51 | ``` | 53 | ``` |
| 54 | |||
| 55 | ### Relay refuses to count | ||
| 56 | |||
| 57 | ``` | ||
| 58 | ["COUNT", <subscription_id>, {"kinds": [4], "authors": [<pubkey>], "#p": [<pubkey>]}] | ||
| 59 | ["CLOSED", <subscription_id>, "auth-required: cannot count other people's DMs"] | ||
| 60 | ``` | ||
| @@ -129,7 +129,7 @@ Errors: | |||
| 129 | ## Example pay invoice flow | 129 | ## Example pay invoice flow |
| 130 | 130 | ||
| 131 | 0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect:` deeplink or configure the connection details manually. | 131 | 0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect:` deeplink or configure the connection details manually. |
| 132 | 1. **client** sends an event to the **wallet service** service with kind `23194`. The content is a `pay_invoice` request. The private key is the secret from the connection string above. | 132 | 1. **client** sends an event to the **wallet service** with kind `23194`. The content is a `pay_invoice` request. The private key is the secret from the connection string above. |
| 133 | 2. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. | 133 | 2. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. |
| 134 | 3. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage. | 134 | 3. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage. |
| 135 | 135 | ||
| @@ -6,148 +6,107 @@ Lists | |||
| 6 | 6 | ||
| 7 | `draft` `optional` | 7 | `draft` `optional` |
| 8 | 8 | ||
| 9 | A "list" event is defined as having a list of public and/or private tags. Public tags will be listed in the event `tags`. Private tags will be encrypted in the event `content`. Encryption for private tags will use [NIP-04 - Encrypted Direct Message](04.md) encryption, using the list author's private and public key for the shared secret. A distinct event kind should be used for each list type created. | 9 | This NIP defines lists of things that users can create. Lists can contain references to anything, and these references can be **public** or **private**. |
| 10 | 10 | ||
| 11 | If a list should only be defined once per user (like the "mute" list) the list is declared as a _replaceable event_. These lists may be referred to as "replaceable lists". Otherwise, the list is a _parameterized replaceable event_ and the list name will be used as the `d` tag. These lists may be referred to as "parameterized replaceable lists". | 11 | Public items in a list are specified in the event `tags` array, while private items are specified in a JSON array that mimics the structure of the event `tags` array, but stringified and encrypted using the same scheme from [NIP-04](04.md) (the shared key is computed using the author's public and private key) and stored in the `.content`. |
| 12 | 12 | ||
| 13 | ## Replaceable List Event Example | 13 | ## Types of lists |
| 14 | 14 | ||
| 15 | Lets say a user wants to create a 'Mute' list and has keys: | 15 | ## Standard lists |
| 16 | ``` | ||
| 17 | priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1 | ||
| 18 | pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d | ||
| 19 | ``` | ||
| 20 | The user wants to publicly include these users: | ||
| 21 | 16 | ||
| 22 | ```json | 17 | Standard lists use non-parameterized replaceable events, meaning users may only have a single list of each kind. They have special meaning and clients may rely on them to augment a user's profile or browsing experience. |
| 23 | ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], | ||
| 24 | ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"] | ||
| 25 | ``` | ||
| 26 | and privately include these users (below is the JSON that would be encrypted and placed in the event content): | ||
| 27 | 18 | ||
| 28 | ```json | 19 | For example, _mute lists_ can contain the public keys of spammers and bad actors users don't want to see in their feeds or receive annoying notifications from. |
| 29 | [ | ||
| 30 | ["p", "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"], | ||
| 31 | ["p", "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168"] | ||
| 32 | ] | ||
| 33 | ``` | ||
| 34 | 20 | ||
| 35 | Then the user would create a 'Mute' list event like below: | 21 | | name | kind | description | expected tag items | |
| 22 | | --- | --- | --- | --- | | ||
| 23 | | Mute list | 10000 | things the user doesn't want to see in their feeds | `"p"` (pubkeys), `"t"` (hashtags), `"word"` (lowercase string), `"e"` (threads) | | ||
| 24 | | Pinned notes | 10001 | events the user intends to showcase in their profile page | `"e"` (kind:1 notes) | | ||
| 25 | | Bookmarks | 10003 | uncategorized, "global" list of things a user wants to save | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r" (URLs)` | | ||
| 26 | | Communities | 10004 | [NIP-72](72.md) communities the user belongs to | `"a"` (kind:34550 community definitions) | | ||
| 27 | | Public chats | 10005 | [NIP-28](28.md) chat channels the user is in | `"e"` (kind:40 channel definitions) | | ||
| 28 | | Blocked relays | 10006 | relays clients should never connect to | `"relay"` (relay URLs) | | ||
| 29 | | Search relays | 10007 | relays clients should use when performing search queries | `"relay"` (relay URLs) | | ||
| 30 | | Interests | 10015 | topics a user may be interested in and pointers | `"t"` (hashtags) and `"a" (kind:30015 interest set)` | | ||
| 31 | | Emojis | 10030 | user preferred emojis and pointers to emoji sets | `"emoji"` (see [NIP-30](30.md)) and `"a"` (kind:30030 emoji set) | | ||
| 36 | 32 | ||
| 37 | ```json | 33 | ## Sets |
| 38 | { | ||
| 39 | "kind": 10000, | ||
| 40 | "tags": [ | ||
| 41 | ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], | ||
| 42 | ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"], | ||
| 43 | ], | ||
| 44 | "content": "VezuSvWak++ASjFMRqBPWS3mK5pZ0vRLL325iuIL4S+r8n9z+DuMau5vMElz1tGC/UqCDmbzE2kwplafaFo/FnIZMdEj4pdxgptyBV1ifZpH3TEF6OMjEtqbYRRqnxgIXsuOSXaerWgpi0pm+raHQPseoELQI/SZ1cvtFqEUCXdXpa5AYaSd+quEuthAEw7V1jP+5TDRCEC8jiLosBVhCtaPpLcrm8HydMYJ2XB6Ixs=?iv=/rtV49RFm0XyFEwG62Eo9A==", | ||
| 45 | ...other fields | ||
| 46 | } | ||
| 47 | ``` | ||
| 48 | 34 | ||
| 35 | Sets are lists with well-defined meaning that can enhance the functionality and the UI of clients that rely on them. Unlike standard lists, users are expected to have more than one set of each kind, therefore each of them must be assigned a different `"d"` identifier. | ||
| 49 | 36 | ||
| 50 | ## Parameterized Replaceable List Event Example | 37 | For example, _relay sets_ can be displayed in a dropdown UI to give users the option to switch to which relays they will publish an event or from which relays they will read the replies to an event; _curation sets_ can be used by apps to showcase curations made by others tagged to different topics. |
| 51 | 38 | ||
| 52 | Lets say a user wants to create a 'Categorized People' list of `nostr` people and has keys: | 39 | Aside from their main identifier, the `"d"` tag, sets can optionally have a `"title"`, an `"image"` and a `"description"` tags that can be used to enhance their UI. |
| 53 | ``` | ||
| 54 | priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1 | ||
| 55 | pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d | ||
| 56 | ``` | ||
| 57 | The user wants to publicly include these users: | ||
| 58 | 40 | ||
| 59 | ```json | 41 | | name | kind | description | expected tag items | |
| 60 | ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], | 42 | | --- | --- | --- | --- | |
| 61 | ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"] | 43 | | Follow sets | 30000 | categorized groups of users a client may choose to check out in different circumstances | `"p"` (pubkeys) | |
| 62 | ``` | 44 | | Relay sets | 30002 | user-defined relay groups the user can easily pick and choose from during various operations | `"relay"` (relay URLs) | |
| 63 | and privately include these users (below is the JSON that would be encrypted and placed in the event content): | 45 | | Bookmark sets | 30003 | user-defined bookmarks categories , for when bookmarks must be in labeled separate groups | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r" (URLs)` | |
| 46 | | Curation sets | 30004 | groups of articles picked by users as interesting and/or belonging to the same category | `"a"` (kind:30023 articles), `"e"` (kind:1 notes) | | ||
| 47 | | Interest sets | 30015 | interest topics represented by a bunch of "hashtags" | `"t"` (hashtags) | | ||
| 48 | | Emoji sets | 30030 | categorized emoji groups | `"emoji"` (see [NIP-30](30.md)) | | ||
| 64 | 49 | ||
| 65 | ```json | 50 | ## Deprecated standard lists |
| 66 | [ | 51 | |
| 67 | ["p", "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"], | 52 | Some clients have used these lists in the past, but they should work on transitioning to the [standard formats](#standard-lists) above. |
| 68 | ["p", "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168"] | 53 | |
| 69 | ] | 54 | | kind | "d" tag | use instead | |
| 70 | ``` | 55 | | --- | --- | --- | |
| 56 | | 30000 | `"mute"` | kind 10000 _mute list_ | | ||
| 57 | | 30001 | `"pin"` | kind 10001 _pin list_ | | ||
| 58 | | 30001 | `"bookmark"` | kind 10003 _bookmarks list_ | | ||
| 59 | | 30001 | `"communities"` | kind 10004 _communities list_ | | ||
| 60 | |||
| 61 | ## Examples | ||
| 71 | 62 | ||
| 72 | Then the user would create a 'Categorized People' list event like below: | 63 | ### A _mute list_ with some public items and some encrypted items |
| 73 | 64 | ||
| 74 | ```json | 65 | ```json |
| 75 | { | 66 | { |
| 76 | "kind": 30000, | 67 | "id": "a92a316b75e44cfdc19986c634049158d4206fcc0b7b9c7ccbcdabe28beebcd0", |
| 68 | "pubkey": "854043ae8f1f97430ca8c1f1a090bdde6488bd5115c7a45307a2a212750ae4cb", | ||
| 69 | "created_at": 1699597889, | ||
| 70 | "kind": 10000, | ||
| 77 | "tags": [ | 71 | "tags": [ |
| 78 | ["d", "nostr"], | 72 | ["p", "07caba282f76441955b695551c3c5c742e5b9202a3784780f8086fdcdc1da3a9"], |
| 79 | ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], | 73 | ["p", "a55c15f5e41d5aebd236eca5e0142789c5385703f1a7485aa4b38d94fd18dcc4"] |
| 80 | ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"], | ||
| 81 | ], | 74 | ], |
| 82 | "content": "VezuSvWak++ASjFMRqBPWS3mK5pZ0vRLL325iuIL4S+r8n9z+DuMau5vMElz1tGC/UqCDmbzE2kwplafaFo/FnIZMdEj4pdxgptyBV1ifZpH3TEF6OMjEtqbYRRqnxgIXsuOSXaerWgpi0pm+raHQPseoELQI/SZ1cvtFqEUCXdXpa5AYaSd+quEuthAEw7V1jP+5TDRCEC8jiLosBVhCtaPpLcrm8HydMYJ2XB6Ixs=?iv=/rtV49RFm0XyFEwG62Eo9A==", | 75 | "content": "TJob1dQrf2ndsmdbeGU+05HT5GMnBSx3fx8QdDY/g3NvCa7klfzgaQCmRZuo1d3WQjHDOjzSY1+MgTK5WjewFFumCcOZniWtOMSga9tJk1ky00tLoUUzyLnb1v9x95h/iT/KpkICJyAwUZ+LoJBUzLrK52wNTMt8M5jSLvCkRx8C0BmEwA/00pjOp4eRndy19H4WUUehhjfV2/VV/k4hMAjJ7Bb5Hp9xdmzmCLX9+64+MyeIQQjQAHPj8dkSsRahP7KS3MgMpjaF8nL48Bg5suZMxJayXGVp3BLtgRZx5z5nOk9xyrYk+71e2tnP9IDvSMkiSe76BcMct+m7kGVrRcavDI4n62goNNh25IpghT+a1OjjkpXt9me5wmaL7fxffV1pchdm+A7KJKIUU3kLC7QbUifF22EucRA9xiEyxETusNludBXN24O3llTbOy4vYFsq35BeZl4v1Cse7n2htZicVkItMz3wjzj1q1I1VqbnorNXFgllkRZn4/YXfTG/RMnoK/bDogRapOV+XToZ+IvsN0BqwKSUDx+ydKpci6htDRF2WDRkU+VQMqwM0CoLzy2H6A2cqyMMMD9SLRRzBg==?iv=S3rFeFr1gsYqmQA7bNnNTQ==", |
| 83 | ...other fields | 76 | "sig": "1173822c53261f8cffe7efbf43ba4a97a9198b3e402c2a1df130f42a8985a2d0d3430f4de350db184141e45ca844ab4e5364ea80f11d720e36357e1853dba6ca" |
| 84 | } | 77 | } |
| 85 | ``` | 78 | ``` |
| 86 | 79 | ||
| 87 | Lets say a user wants to create a 'Categorized Bookmarks' list of `bookmarks` and has keys: | 80 | ### A _curation set_ of articles and notes about yaks |
| 88 | ``` | ||
| 89 | priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1 | ||
| 90 | pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d | ||
| 91 | ``` | ||
| 92 | The user wants to publicly include these bookmarks: | ||
| 93 | |||
| 94 | ```json | ||
| 95 | ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"], | ||
| 96 | ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], | ||
| 97 | ["r", "https://github.com/nostr-protocol/nostr", "Nostr repository"], | ||
| 98 | ``` | ||
| 99 | and privately include these bookmarks (below is the JSON that would be encrypted and placed in the event content): | ||
| 100 | 81 | ||
| 101 | ```json | ||
| 102 | [ | ||
| 103 | ["r", "https://my-private.bookmark", "My private bookmark"], | ||
| 104 | ["a", "30001:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], | ||
| 105 | ] | ||
| 106 | ``` | 82 | ``` |
| 107 | |||
| 108 | Then the user would create a 'Categorized Bookmarks' list event like below: | ||
| 109 | |||
| 110 | ```json | ||
| 111 | { | 83 | { |
| 112 | "kind": 30001, | 84 | "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", |
| 85 | "pubkey": "d6dc95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c", | ||
| 86 | "created_at": 1695327657, | ||
| 87 | "kind": 30004, | ||
| 113 | "tags": [ | 88 | "tags": [ |
| 114 | ["d", "bookmarks"], | 89 | ["d", "jvdy9i4"], |
| 115 | ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"], | 90 | ["name", "Yaks"], |
| 116 | ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], | 91 | ["picture", "https://cdn.britannica.com/40/188540-050-9AC748DE/Yak-Himalayas-Nepal.jpg"], |
| 117 | ["r", "https://github.com/nostr-protocol/nostr", "Nostr repository"], | 92 | ["about", "The domestic yak, also known as the Tartary ox, grunting ox, or hairy cattle, is a species of long-haired domesticated cattle found throughout the Himalayan region of the Indian subcontinent, the Tibetan Plateau, Gilgit-Baltistan, Tajikistan and as far north as Mongolia and Siberia."], |
| 93 | ["a", "30023:26dc95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:95ODQzw3ajNoZ8SyMDOzQ"], | ||
| 94 | ["a", "30023:54af95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:1-MYP8dAhramH9J5gJWKx"], | ||
| 95 | ["a", "30023:f8fe95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:D2Tbd38bGrFvU0bIbvSMt"], | ||
| 96 | ["e", "d78ba0d5dce22bfff9db0a9e996c9ef27e2c91051de0c4e1da340e0326b4941e"] | ||
| 118 | ], | 97 | ], |
| 119 | "content": "y3AyaLJfnmYr9x9Od9o4aYrmL9+Ynmsim5y2ONrU0urOTq+V81CyAthQ2mUOWE9xwGgrizhY7ILdQwWhy6FK0sA33GHtC0egUJw1zIdknPe7BZjznD570yk/8RXYgGyDKdexME+RMYykrnYFxq1+y/h00kmJg4u+Gpn+ZjmVhNYxl9b+TiBOAXG9UxnK/H0AmUqDpcldn6+j1/AiStwYZhD1UZ3jzDIk2qcCDy7MlGnYhSP+kNmG+2b0T/D1L0Z7?iv=PGJJfPE84gacAh7T0e6duQ==", | 98 | "content": "", |
| 120 | ...other fields | 99 | "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" |
| 121 | } | 100 | } |
| 122 | ``` | 101 | ``` |
| 123 | 102 | ||
| 124 | ## List Event Kinds | 103 | ## Encryption process pseudocode |
| 125 | |||
| 126 | | kind | list type | | ||
| 127 | | ------ | ----------------------- | | ||
| 128 | | 10000 | Mute | | ||
| 129 | | 10001 | Pin | | ||
| 130 | | 30000 | Categorized People | | ||
| 131 | | 30001 | Categorized Bookmarks | | ||
| 132 | | 30002 | Categorized Relay Sets | | ||
| 133 | 104 | ||
| 134 | 105 | ```scala | |
| 135 | ### Mute List | 106 | val private_items = [ |
| 136 | 107 | ["p", "07caba282f76441955b695551c3c5c742e5b9202a3784780f8086fdcdc1da3a9"], | |
| 137 | An event with kind `10000` is defined as a replaceable list event for listing content a user wants to mute. Any standardized tag can be included in a Mute List. | 108 | ["a", "a55c15f5e41d5aebd236eca5e0142789c5385703f1a7485aa4b38d94fd18dcc4"], |
| 138 | 109 | ] | |
| 139 | ### Pin List | 110 | val base64blob = nip04.encrypt(json.encode_to_string(private_items)) |
| 140 | 111 | event.content = base64blob | |
| 141 | An event with kind `10001` is defined as a replaceable list event for listing content a user wants to pin. Any standardized tag can be included in a Pin List. | 112 | ``` |
| 142 | |||
| 143 | ### Categorized People List | ||
| 144 | |||
| 145 | An event with kind `30000` is defined as a parameterized replaceable list event for categorizing people. The 'd' parameter for this event holds the category name of the list. The tags included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). | ||
| 146 | |||
| 147 | ### Categorized Bookmarks List | ||
| 148 | |||
| 149 | An event of kind `30001` is defined as a parameterized replaceable list event for categorizing bookmarks. The 'd' parameter for this event holds the category name of the list. The bookmark lists may contain metadata tags such as 'title', 'image', 'summary' as defined in [NIP-23 - Long-form Content](23.md). Any standardized tag can be included in a Categorized Bookmark List. | ||
| 150 | |||
| 151 | ### Categorized Relay Set | ||
| 152 | |||
| 153 | An event of kind `30002` is defined as a parameterized replaceable list event for categorizing relays. The 'd' parameter for this event holds the category name of the list. The relays lists may contain metadata tags such as 'title', 'image', 'summary' as defined in [NIP-23 - Long-form Content](23.md). These sets can be used by clients in order to determine which relays to query in different scenarios. | ||
| @@ -6,7 +6,7 @@ Live Activities | |||
| 6 | 6 | ||
| 7 | `draft` `optional` | 7 | `draft` `optional` |
| 8 | 8 | ||
| 9 | 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. | 9 | Service providers want to offer live activities to the Nostr network in such a way that participants can easily log and query by clients. This NIP describes a general framework to advertise the involvement of pubkeys in such live activities. |
| 10 | 10 | ||
| 11 | ## Concepts | 11 | ## Concepts |
| 12 | 12 | ||
| @@ -36,7 +36,7 @@ A `zap request` is an event of kind `9734` that is _not_ published to relays, bu | |||
| 36 | In addition, the event MAY include the following tags: | 36 | In addition, the event MAY include the following tags: |
| 37 | 37 | ||
| 38 | - `e` is an optional hex-encoded event id. Clients MUST include this if zapping an event rather than a person. | 38 | - `e` is an optional hex-encoded event id. Clients MUST include this if zapping an event rather than a person. |
| 39 | - `a` is an optional NIP-33 event coordinate that allows tipping parameterized replaceable events such as NIP-23 long-form notes. | 39 | - `a` is an optional event coordinate that allows tipping parameterized replaceable events such as NIP-23 long-form notes. |
| 40 | 40 | ||
| 41 | Example: | 41 | Example: |
| 42 | 42 | ||
| @@ -110,7 +110,7 @@ When a client sends a `zap request` event to a server's lnurl-pay callback URL, | |||
| 110 | 4. It MUST have 0 or 1 `e` tags | 110 | 4. It MUST have 0 or 1 `e` tags |
| 111 | 5. There should be a `relays` tag with the relays to send the `zap receipt` to. | 111 | 5. There should be a `relays` tag with the relays to send the `zap receipt` to. |
| 112 | 6. If there is an `amount` tag, it MUST be equal to the `amount` query parameter. | 112 | 6. If there is an `amount` tag, it MUST be equal to the `amount` query parameter. |
| 113 | 7. If there is an `a` tag, it MUST be a valid NIP-33 event coordinate | 113 | 7. If there is an `a` tag, it MUST be a valid event coordinate |
| 114 | 114 | ||
| 115 | The event MUST then be stored for use later, when the invoice is paid. | 115 | The event MUST then be stored for use later, when the invoice is paid. |
| 116 | 116 | ||
| @@ -62,8 +62,6 @@ Users MAY choose to decorate their profiles with badges for fame, notoriety, rec | |||
| 62 | 62 | ||
| 63 | ### Recommendations | 63 | ### Recommendations |
| 64 | 64 | ||
| 65 | Badge issuers MAY include some Proof of Work as per [NIP-13](13.md) when minting Badge Definitions or Badge Awards to embed them with a combined energy cost, arguably making them more special and valuable for users that wish to collect them. | ||
| 66 | |||
| 67 | Clients MAY whitelist badge issuers (pubkeys) for the purpose of ensuring they retain a valuable/special factor for their users. | 65 | Clients MAY whitelist badge issuers (pubkeys) for the purpose of ensuring they retain a valuable/special factor for their users. |
| 68 | 66 | ||
| 69 | Badge image recommended aspect ratio is 1:1 with a high-res size of 1024x1024 pixels. | 67 | Badge image recommended aspect ratio is 1:1 with a high-res size of 1024x1024 pixels. |
| @@ -35,6 +35,8 @@ Example event: | |||
| 35 | The following tags are OPTIONAL. | 35 | The following tags are OPTIONAL. |
| 36 | 36 | ||
| 37 | - `closed_at` - timestamp for determining which zaps are included in the tally. Zap receipts published after the `closed_at` timestamp SHOULD NOT count towards the goal progress. | 37 | - `closed_at` - timestamp for determining which zaps are included in the tally. Zap receipts published after the `closed_at` timestamp SHOULD NOT count towards the goal progress. |
| 38 | - `image` - an image for the goal | ||
| 39 | - `summary` - a brief description | ||
| 38 | 40 | ||
| 39 | ```json | 41 | ```json |
| 40 | { | 42 | { |
| @@ -43,6 +45,8 @@ The following tags are OPTIONAL. | |||
| 43 | ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...], | 45 | ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...], |
| 44 | ["amount", "210000"], | 46 | ["amount", "210000"], |
| 45 | ["closed_at", "<unix timestamp in seconds>"], | 47 | ["closed_at", "<unix timestamp in seconds>"], |
| 48 | ["image", "<image URL>"], | ||
| 49 | ["summary", "<description of the goal>"], | ||
| 46 | ], | 50 | ], |
| 47 | "content": "Nostrasia travel expenses", | 51 | "content": "Nostrasia travel expenses", |
| 48 | ... | 52 | ... |
| @@ -65,7 +65,7 @@ The third value of the tag SHOULD be the platform where this recommendation migh | |||
| 65 | 65 | ||
| 66 | * `content` is an optional `metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.) | 66 | * `content` is an optional `metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.) |
| 67 | * `k` tags' value is the event kind that is supported by this `kind:31990`. | 67 | * `k` tags' value is the event kind that is supported by this `kind:31990`. |
| 68 | Using a `k` tag(s) (instead of having the kind onf the NIP-33 `d` tag) provides: | 68 | Using a `k` tag(s) (instead of having the kind of the `d` tag) provides: |
| 69 | * Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same. | 69 | * Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same. |
| 70 | * The same pubkey can have multiple events with different apps that handle the same event kind. | 70 | * The same pubkey can have multiple events with different apps that handle the same event kind. |
| 71 | * `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application. | 71 | * `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application. |
| @@ -74,14 +74,14 @@ Multiple tags might be registered by the app, following NIP-19 nomenclature as t | |||
| 74 | 74 | ||
| 75 | A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag. | 75 | A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag. |
| 76 | 76 | ||
| 77 | ## Client tag | 77 | # Client tag |
| 78 | When publishing events, clients MAY include a `client` tag in the same format as the recommendation event's `a` tags. This has privacy implications for users, so clients SHOULD allow users to opt-out of using this tag. | 78 | When publishing events, clients MAY include a `client` tag. Identifying the client that published the note. This tag is a tuple of `name`, `address` identifying a handler event and, a relay `hint` for finding the handler event. This has privacy implications for users, so clients SHOULD allow users to opt-out of using this tag. |
| 79 | 79 | ||
| 80 | ```json | 80 | ```json |
| 81 | { | 81 | { |
| 82 | "kind": 1, | 82 | "kind": 1, |
| 83 | "tags": [ | 83 | "tags": [ |
| 84 | ["client", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios"] | 84 | ["client", "My Client", "31990:app1-pubkey:<d-identifier>", "wss://relay1"] |
| 85 | ] | 85 | ] |
| 86 | ... | 86 | ... |
| 87 | } | 87 | } |
| @@ -34,7 +34,7 @@ There are two actors in the workflow described in this NIP: | |||
| 34 | * Service providers (npubs who fulfill jobs) | 34 | * Service providers (npubs who fulfill jobs) |
| 35 | 35 | ||
| 36 | ## Job request (`kind:5000-5999`) | 36 | ## Job request (`kind:5000-5999`) |
| 37 | A request to process data, published by a customer. This event signals that an customer is interested in receiving the result of some kind of compute. | 37 | A request to process data, published by a customer. This event signals that a customer is interested in receiving the result of some kind of compute. |
| 38 | 38 | ||
| 39 | ```json | 39 | ```json |
| 40 | { | 40 | { |
| @@ -22,7 +22,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 22 | ## List | 22 | ## List |
| 23 | 23 | ||
| 24 | - [NIP-01: Basic protocol flow description](01.md) | 24 | - [NIP-01: Basic protocol flow description](01.md) |
| 25 | - [NIP-02: Contact List and Petnames](02.md) | 25 | - [NIP-02: Follow List](02.md) |
| 26 | - [NIP-03: OpenTimestamps Attestations for Events](03.md) | 26 | - [NIP-03: OpenTimestamps Attestations for Events](03.md) |
| 27 | - [NIP-04: Encrypted Direct Message](04.md) | 27 | - [NIP-04: Encrypted Direct Message](04.md) |
| 28 | - [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md) | 28 | - [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md) |
| @@ -38,7 +38,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 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-21: `nostr:` URI scheme](21.md) | 40 | - [NIP-21: `nostr:` URI scheme](21.md) |
| 41 | - [NIP-22: Event `created_at` Limits](22.md) | ||
| 42 | - [NIP-23: Long-form Content](23.md) | 41 | - [NIP-23: Long-form Content](23.md) |
| 43 | - [NIP-24: Extra metadata fields and tags](24.md) | 42 | - [NIP-24: Extra metadata fields and tags](24.md) |
| 44 | - [NIP-25: Reactions](25.md) | 43 | - [NIP-25: Reactions](25.md) |
| @@ -76,66 +75,82 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 76 | - [NIP-99: Classified Listings](99.md) | 75 | - [NIP-99: Classified Listings](99.md) |
| 77 | 76 | ||
| 78 | ## Event Kinds | 77 | ## Event Kinds |
| 79 | | kind | description | NIP | | 78 | | kind | description | NIP | |
| 80 | | ------------- | -------------------------- | ----------- | | 79 | | ------------- | -------------------------- | ----------- | |
| 81 | | `0` | Metadata | [1](01.md) | | 80 | | `0` | Metadata | [1](01.md) | |
| 82 | | `1` | Short Text Note | [1](01.md) | | 81 | | `1` | Short Text Note | [1](01.md) | |
| 83 | | `2` | Recommend Relay | | | 82 | | `2` | Recommend Relay | | |
| 84 | | `3` | Contacts | [2](02.md) | | 83 | | `3` | Follows | [2](02.md) | |
| 85 | | `4` | Encrypted Direct Messages | [4](04.md) | | 84 | | `4` | Encrypted Direct Messages | [4](04.md) | |
| 86 | | `5` | Event Deletion | [9](09.md) | | 85 | | `5` | Event Deletion | [9](09.md) | |
| 87 | | `6` | Repost | [18](18.md) | | 86 | | `6` | Repost | [18](18.md) | |
| 88 | | `7` | Reaction | [25](25.md) | | 87 | | `7` | Reaction | [25](25.md) | |
| 89 | | `8` | Badge Award | [58](58.md) | | 88 | | `8` | Badge Award | [58](58.md) | |
| 90 | | `16` | Generic Repost | [18](18.md) | | 89 | | `16` | Generic Repost | [18](18.md) | |
| 91 | | `40` | Channel Creation | [28](28.md) | | 90 | | `40` | Channel Creation | [28](28.md) | |
| 92 | | `41` | Channel Metadata | [28](28.md) | | 91 | | `41` | Channel Metadata | [28](28.md) | |
| 93 | | `42` | Channel Message | [28](28.md) | | 92 | | `42` | Channel Message | [28](28.md) | |
| 94 | | `43` | Channel Hide Message | [28](28.md) | | 93 | | `43` | Channel Hide Message | [28](28.md) | |
| 95 | | `44` | Channel Mute User | [28](28.md) | | 94 | | `44` | Channel Mute User | [28](28.md) | |
| 96 | | `1063` | File Metadata | [94](94.md) | | 95 | | `1040` | OpenTimestamps | [03](03.md) | |
| 97 | | `1311` | Live Chat Message | [53](53.md) | | 96 | | `1063` | File Metadata | [94](94.md) | |
| 98 | | `1040` | OpenTimestamps | [03](03.md) | | 97 | | `1311` | Live Chat Message | [53](53.md) | |
| 99 | | `1971` | Problem Tracker | [1971](https://github.com/nostrocket/NIPS/blob/main/Problems.md) | | 98 | | `1971` | Problem Tracker | [nostrocket][nostrocket] | |
| 100 | | `1984` | Reporting | [56](56.md) | | 99 | | `1984` | Reporting | [56](56.md) | |
| 101 | | `1985` | Label | [32](32.md) | | 100 | | `1985` | Label | [32](32.md) | |
| 102 | | `4550` | Community Post Approval | [72](72.md) | | 101 | | `4550` | Community Post Approval | [72](72.md) | |
| 103 | | `5000`-`5999` | Job Request | [90](90.md) | | 102 | | `5000`-`5999` | Job Request | [90](90.md) | |
| 104 | | `6000`-`6999` | Job Result | [90](90.md) | | 103 | | `6000`-`6999` | Job Result | [90](90.md) | |
| 105 | | `7000` | Job Feedback | [90](90.md) | | 104 | | `7000` | Job Feedback | [90](90.md) | |
| 106 | | `9041` | Zap Goal | [75](75.md) | | 105 | | `9041` | Zap Goal | [75](75.md) | |
| 107 | | `9734` | Zap Request | [57](57.md) | | 106 | | `9734` | Zap Request | [57](57.md) | |
| 108 | | `9735` | Zap | [57](57.md) | | 107 | | `9735` | Zap | [57](57.md) | |
| 109 | | `9802` | Highlights | [84](84.md) | | 108 | | `9802` | Highlights | [84](84.md) | |
| 110 | | `10000` | Mute List | [51](51.md) | | 109 | | `10000` | Mute list | [51](51.md) | |
| 111 | | `10001` | Pin List | [51](51.md) | | 110 | | `10001` | Pin list | [51](51.md) | |
| 112 | | `10002` | Relay List Metadata | [65](65.md) | | 111 | | `10002` | Relay List Metadata | [65](65.md) | |
| 113 | | `13194` | Wallet Info | [47](47.md) | | 112 | | `10003` | Bookmark list | [51](51.md) | |
| 114 | | `22242` | Client Authentication | [42](42.md) | | 113 | | `10004` | Communities list | [51](51.md) | |
| 115 | | `23194` | Wallet Request | [47](47.md) | | 114 | | `10005` | Public chats list | [51](51.md) | |
| 116 | | `23195` | Wallet Response | [47](47.md) | | 115 | | `10006` | Blocked relays list | [51](51.md) | |
| 117 | | `24133` | Nostr Connect | [46](46.md) | | 116 | | `10007` | Search relays list | [51](51.md) | |
| 118 | | `27235` | HTTP Auth | [98](98.md) | | 117 | | `10015` | Interests list | [51](51.md) | |
| 119 | | `30000` | Categorized People List | [51](51.md) | | 118 | | `10030` | User emoji list | [51](51.md) | |
| 120 | | `30001` | Categorized Bookmark List | [51](51.md) | | 119 | | `13194` | Wallet Info | [47](47.md) | |
| 121 | | `30008` | Profile Badges | [58](58.md) | | 120 | | `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] | |
| 122 | | `30009` | Badge Definition | [58](58.md) | | 121 | | `22242` | Client Authentication | [42](42.md) | |
| 123 | | `30017` | Create or update a stall | [15](15.md) | | 122 | | `23194` | Wallet Request | [47](47.md) | |
| 124 | | `30018` | Create or update a product | [15](15.md) | | 123 | | `23195` | Wallet Response | [47](47.md) | |
| 125 | | `30023` | Long-form Content | [23](23.md) | | 124 | | `24133` | Nostr Connect | [46](46.md) | |
| 126 | | `30024` | Draft Long-form Content | [23](23.md) | | 125 | | `27235` | HTTP Auth | [98](98.md) | |
| 127 | | `30078` | Application-specific Data | [78](78.md) | | 126 | | `30000` | Follow sets | [51](51.md) | |
| 128 | | `30311` | Live Event | [53](53.md) | | 127 | | `30001` | Generic lists | [51](51.md) | |
| 129 | | `30315` | User Statuses | [38](38.md) | | 128 | | `30002` | Relay sets | [51](51.md) | |
| 130 | | `30402` | Classified Listing | [99](99.md) | | 129 | | `30003` | Bookmark sets | [51](51.md) | |
| 131 | | `30403` | Draft Classified Listing | [99](99.md) | | 130 | | `30004` | Curation sets | [51](51.md) | |
| 132 | | `31922` | Date-Based Calendar Event | [52](52.md) | | 131 | | `30008` | Profile Badges | [58](58.md) | |
| 133 | | `31923` | Time-Based Calendar Event | [52](52.md) | | 132 | | `30009` | Badge Definition | [58](58.md) | |
| 134 | | `31924` | Calendar | [52](52.md) | | 133 | | `30015` | Interest sets | [51](51.md) | |
| 135 | | `31925` | Calendar Event RSVP | [52](52.md) | | 134 | | `30017` | Create or update a stall | [15](15.md) | |
| 136 | | `31989` | Handler recommendation | [89](89.md) | | 135 | | `30018` | Create or update a product | [15](15.md) | |
| 137 | | `31990` | Handler information | [89](89.md) | | 136 | | `30023` | Long-form Content | [23](23.md) | |
| 138 | | `34550` | Community Definition | [72](72.md) | | 137 | | `30024` | Draft Long-form Content | [23](23.md) | |
| 138 | | `30030` | Emoji sets | [51](51.md) | | ||
| 139 | | `30078` | Application-specific Data | [78](78.md) | | ||
| 140 | | `30311` | Live Event | [53](53.md) | | ||
| 141 | | `30315` | User Statuses | [38](38.md) | | ||
| 142 | | `30402` | Classified Listing | [99](99.md) | | ||
| 143 | | `30403` | Draft Classified Listing | [99](99.md) | | ||
| 144 | | `31922` | Date-Based Calendar Event | [52](52.md) | | ||
| 145 | | `31923` | Time-Based Calendar Event | [52](52.md) | | ||
| 146 | | `31924` | Calendar | [52](52.md) | | ||
| 147 | | `31925` | Calendar Event RSVP | [52](52.md) | | ||
| 148 | | `31989` | Handler recommendation | [89](89.md) | | ||
| 149 | | `31990` | Handler information | [89](89.md) | | ||
| 150 | | `34550` | Community Definition | [72](72.md) | | ||
| 151 | |||
| 152 | [nostrocket]: https://github.com/nostrocket/NIPS/blob/main/Problems.md | ||
| 153 | [lnpub]: https://github.com/shocknet/Lightning.Pub/blob/master/proto/autogenerated/client.md | ||
| 139 | 154 | ||
| 140 | ## Message types | 155 | ## Message types |
| 141 | 156 | ||
| @@ -157,6 +172,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | |||
| 157 | | `EVENT` | used to send events requested to clients | [01](01.md) | | 172 | | `EVENT` | used to send events requested to clients | [01](01.md) | |
| 158 | | `NOTICE` | used to send human-readable messages to clients | [01](01.md) | | 173 | | `NOTICE` | used to send human-readable messages to clients | [01](01.md) | |
| 159 | | `OK` | used to notify clients if an EVENT was successful | [01](01.md) | | 174 | | `OK` | used to notify clients if an EVENT was successful | [01](01.md) | |
| 175 | | `CLOSED` | used to notify clients that a REQ was ended and why | [01](01.md) | | ||
| 160 | | `AUTH` | used to send authentication challenges | [42](42.md) | | 176 | | `AUTH` | used to send authentication challenges | [42](42.md) | |
| 161 | | `COUNT` | used to send requested event counts to clients | [45](45.md) | | 177 | | `COUNT` | used to send requested event counts to clients | [45](45.md) | |
| 162 | 178 | ||
| @@ -170,7 +186,6 @@ Please update these lists when proposing NIPs introducing new event kinds. | |||
| 170 | | `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) | | 186 | | `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) | |
| 171 | | `a` | coordinates to an event | relay URL | [01](01.md) | | 187 | | `a` | coordinates to an event | relay URL | [01](01.md) | |
| 172 | | `d` | identifier | -- | [01](01.md) | | 188 | | `d` | identifier | -- | [01](01.md) | |
| 173 | | `alt` | summary | -- | [31](31.md) | | ||
| 174 | | `g` | geohash | -- | [52](52.md) | | 189 | | `g` | geohash | -- | [52](52.md) | |
| 175 | | `i` | identity | proof | [39](39.md) | | 190 | | `i` | identity | proof | [39](39.md) | |
| 176 | | `k` | kind number (string) | -- | [18](18.md), [25](25.md), [72](72.md) | | 191 | | `k` | kind number (string) | -- | [18](18.md), [25](25.md), [72](72.md) | |
| @@ -180,13 +195,16 @@ Please update these lists when proposing NIPs introducing new event kinds. | |||
| 180 | | `r` | a reference (URL, etc) | petname | | | 195 | | `r` | a reference (URL, etc) | petname | | |
| 181 | | `r` | relay url | marker | [65](65.md) | | 196 | | `r` | relay url | marker | [65](65.md) | |
| 182 | | `t` | hashtag | -- | | | 197 | | `t` | hashtag | -- | | |
| 198 | | `alt` | summary | -- | [31](31.md) | | ||
| 183 | | `amount` | millisatoshis, stringified | -- | [57](57.md) | | 199 | | `amount` | millisatoshis, stringified | -- | [57](57.md) | |
| 184 | | `bolt11` | `bolt11` invoice | -- | [57](57.md) | | 200 | | `bolt11` | `bolt11` invoice | -- | [57](57.md) | |
| 185 | | `challenge` | challenge string | -- | [42](42.md) | | 201 | | `challenge` | challenge string | -- | [42](42.md) | |
| 202 | | `client` | name, address | relay URL | [89](89.md) | | ||
| 186 | | `content-warning` | reason | -- | [36](36.md) | | 203 | | `content-warning` | reason | -- | [36](36.md) | |
| 187 | | `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) | | 204 | | `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) | |
| 188 | | `description` | invoice/badge description | -- | [57](57.md), [58](58.md) | | 205 | | `description` | invoice/badge description | -- | [57](57.md), [58](58.md) | |
| 189 | | `emoji` | shortcode, image URL | -- | [30](30.md) | | 206 | | `emoji` | shortcode, image URL | -- | [30](30.md) | |
| 207 | | `encrypted` | -- | -- | [90](90.md) | | ||
| 190 | | `expiration` | unix timestamp (string) | -- | [40](40.md) | | 208 | | `expiration` | unix timestamp (string) | -- | [40](40.md) | |
| 191 | | `goal` | event id (hex) | relay URL | [75](75.md) | | 209 | | `goal` | event id (hex) | relay URL | [75](75.md) | |
| 192 | | `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) | | 210 | | `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) | |