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:31989and, 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"]
],
// other fields...
}
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>],
["latest", "35128:<application-pubkey>:<site-d-identifier>", "wss://relay1"],
["next", "35128:<application-pubkey>:<next-site-d-identifier>", "wss://relay1"],
["web", "https://..../a/<bech32>", "nevent"],
["web", "https://..../p/<bech32>", "nprofile"],
["web", "https://..../e/<bech32>"],
["ios", ".../<bech32>"]
],
// other fields...
}
contentis an optionalmetadata-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating thekind:31990is not an application. Ifcontentis empty, thekind:0of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)ktags’ value is the event kind that is supported by thiskind:31990. Using aktag(s) (instead of having the kind of thedtag) provides:- Multiple
ktags 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
- App descriptor events SHOULD tag or otherwise reference related site manifest events when applicable, so clients can discover the deployed site manifest for an application directly from the upstream app descriptor.
- For web applications,
kind:31990events SHOULD includelatestandnexttags referencing related nsite manifests when applicable. These tags use the same shape as anatag: the second element is<kind>:<pubkey>:<d-tag>and the third element is an optional relay hint.latestSHOULD reference the current site manifest for the application, whilenextSHOULD reference the next site manifest intended for rollout or upgrade. bech32in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.
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"]
]
// other fields...
}
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"]
],
// other fields...
}
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": [...] }]
Warning
unrecommended: unnecessarily bloated