6.1 KiB
NIP-89
Recommended Application Handlers
draft
optional
This NIP describes kind:31989
and kind:31990
: a way to discover applications that can handle unknown event-kinds.
Rationale
Nostr's discoverability and transparent event interaction is one of its most interesting/novel mechanics. This NIP provides a simple way for clients to discover applications that handle events of a specific kind to ensure smooth cross-client and cross-kind interactions.
Parties involved
There are three actors to this workflow:
- application that handles a specific event kind (note that an application doesn't necessarily need to be a distinct entity and it could just be the same pubkey as user A)
- Publishes
kind:31990
, detailing how apps should redirect to it
- Publishes
- user A, who recommends an app that handles a specific event kind
- Publishes
kind:31989
- Publishes
- user B, who seeks a recommendation for an app that handles a specific event kind
- Queries for
kind:31989
and, based on results, queries forkind:31990
- Queries for
Events
Recommendation event
{
"kind": 31989,
"pubkey": <recommender-user-pubkey>,
"tags": [
["d", <supported-event-kind>],
["a", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios"],
["a", "31990:app2-pubkey:<d-identifier>", "wss://relay2", "web"]
]
}
The d
tag in kind:31989
is the supported event kind this event is recommending.
Multiple a
tags can appear on the same kind:31989
.
The second value of the tag SHOULD be a relay hint. The third value of the tag SHOULD be the platform where this recommendation might apply.
Handler information
{
"kind": 31990,
"pubkey": "<application-pubkey>",
"content": "<optional-kind:0-style-metadata>",
"tags": [
["d", <random-id>],
["k", <supported-event-kind>],
["web", "https://..../a/<bech32>", "nevent"],
["web", "https://..../p/<bech32>", "nprofile"],
["web", "https://..../e/<bech32>"],
["ios", ".../<bech32>"],
["pff", "preferred feedback format"]
]
}
content
is an optionalmetadata
-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating thekind:31990
is not an application. Ifcontent
is empty, thekind:0
of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)k
tags' value is the event kind that is supported by thiskind:31990
. Using ak
tag(s) (instead of having the kind of thed
tag) provides:- 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. - The same pubkey can have multiple events with different apps that handle the same event kind.
- Multiple
bech32
in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.pff
stands for preferred feedback format and is an optional tag that describes how the application would like to receive additional feedback fromkind:7
reactions. The format specified inpff
is used to inform thefeedback
tag of thekind:7
customer feedback event described in NIP-90 - Data Vending Machine. Bothpff
andfeedback
values should be strings and no commitments to representation are made here; instead applications consuming these tags should work together to align themselves.
Multiple tags might be registered by the app, following NIP-19 nomenclature as the second value of the array.
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.
Client tag
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.
{
"kind": 1,
"tags": [
["client", "My Client", "31990:app1-pubkey:<d-identifier>", "wss://relay1"]
]
...
}
User flow
A user A who uses a non-kind:1
-centric nostr app could choose to announce/recommend a certain kind-handler application.
When user B sees an unknown event kind, e.g. in a social-media centric nostr client, the client would allow user B to interact with the unknown-kind event (e.g. tapping on it).
The client MIGHT query for the user's and the user's follows handler.
Example
User A recommends a kind:31337
-handler
User A might be a user of Zapstr, a kind:31337
-centric client (tracks). Using Zapstr, user A publishes an event recommending Zapstr as a kind:31337
-handler.
{
"kind": 31989,
"tags": [
["d", "31337"],
["a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", <relay-url>, "web"]
],
...
}
User B interacts with a kind:31337
-handler
User B might see in their timeline an event referring to a kind:31337
event (e.g. a kind:1
tagging a kind:31337
).
User B's client, not knowing how to handle a kind:31337
might display the event using its alt
tag (as described in NIP-31). When the user clicks on the event, the application queries for a handler for this kind
:
["REQ", <id>, '[{ "kinds": [31989], "#d": ["31337"], 'authors': [<user>, <users-contact-list>] }]']
User B, who follows User A, sees that kind:31989
event and fetches the a
-tagged event for the app and handler information.
User B's client sees the application's kind:31990
which includes the information to redirect the user to the relevant URL with the desired entity replaced in the URL.
Alternative query bypassing kind:31989
Alternatively, users might choose to query directly for kind:31990
for an event kind. Clients SHOULD be careful doing this and use spam-prevention mechanisms or querying high-quality restricted relays to avoid directing users to malicious handlers.
["REQ", <id>, '[{ "kinds": [31990], "#k": [<desired-event-kind>], 'authors': [...] }]']