Chapter 43 - Relay Ops
43
Nostr Implementation Possibility - Hex № 43

Relay Access Metadata and Requests

A members-only relay that can say who belongs, and a front door where clients ask to get in.

1 Overview

Some relays are private clubs. Only members can write, and sometimes only members can read. Before this NIP, a locked-out user had no protocol-level way to ask for a key. This NIP gives relays a voice and users a doorbell.

The relay side is metadata. A relay publishes events that define member roles, list its members, and announce when a member is added or removed. The relay signs these events with its own identity key: the pubkey in the self field of its NIP-11 information document.

The user side is requests. A user sends a join request with an invite code, asks the relay for an invite code, or sends a leave request to give up access. The relay answers each join request with a plain NIP-01 OK message.

Every event in this NIP carries the NIP-70 protected tag: a tag named -. It marks the event as protected, so other relays must not accept it from anyone except its author.

User Relay 28934 join - 28936 leave 33534 roles - 13534 members - 8000/8001 - 28935 invite Relay events are signed by the NIP-11 "self" pubkey.
Fig. 43-1 — Two directions. The relay publishes access metadata. The user sends access requests.
Event kinds in this NIP
KindNameSignerStorage class
33534Role definitionrelayaddressable
13534Membership listrelayreplaceable
8000Add userrelayregular
8001Remove userrelayregular
28934Join requestuserephemeral
28935Inviterelayephemeral
28936Leave requestuserephemeral

2 Role Definitions — Kind 33534

A relay may publish a kind 33534 event to define a role. A role is a named position that the relay can assign to members. The relay must sign the event with the NIP-11 self pubkey.

Two tags are required:

  • The NIP-70 - tag.
  • A d tag. Its value is the role id.

Four tags are optional:

Optional role tags
TagValue
labelA label for the role.
descriptionA description of the role.
colorA hue value from 0 to 360 for the role.
orderAn order integer for the role. Clients use it for display only.
Wire format - role definition
{
  "kind": 33534,
  "pubkey": <nip11.self>,
  "tags": [
    ["-"],
    ["d", "28b7e50f"],
    ["label", "king"],
    ["description", "ruler of the relay"],
    ["color", "37"],
    ["order", "1"]
  ]
  // ...other fields
}

A relay may treat members with a given role differently in its access policies. The NIP defines no mechanism to inspect those policies at this time.

3 Membership Lists — Kind 13534

A relay may publish a kind 13534 event to list the pubkeys that have access to it. The relay must sign the event with the NIP-11 self pubkey.

Two tags are required:

  • The NIP-70 - tag.
  • One member tag per member. Its value is the member's hex pubkey. Assigned role ids may follow as later elements of the same tag.
Wire format - membership list
{
  "kind": 13534,
  "pubkey": <nip11.self>,
  "tags": [
    ["-"],
    ["member", "c308e1f882c1f1dff2a43d4294239ddeec04e575f2d1aad1fa21ea7684e61fb5"],
    ["member", "ee1d336e13779e4d4c527b988429d96de16088f958cbf6c074676ac9cfd9c958", "28b7e50f"]
  ]
  // ...other fields
}
Warning!

The list is not exhaustive and not authoritative. To determine membership, consult two events: the relay's kind 13534 list and the member's own kind 10010 event.

Tech Note

The source references a kind 10010 event by the member but does not define it and does not link a NIP that does. The pointer is unresolved as written.

4 Add and Remove Announcements — Kinds 8000 / 8001

A relay may publish a kind 8000 event when it adds a member. A relay may publish a kind 8001 event when it removes a member. Both events must be signed with the NIP-11 self pubkey. Both events require two tags:

  • The NIP-70 - tag.
  • A p tag with the member's hex pubkey.
Wire format - add user / remove user
{
  "kind": 8000,  // or 8001 to remove
  "pubkey": <nip11.self>,
  "tags": [
    ["-"],
    ["p", "c308e1f882c1f1dff2a43d4294239ddeec04e575f2d1aad1fa21ea7684e61fb5"]
  ]
  // ...other fields
}

5 Join Request — Kind 28934

A user may send a kind 28934 event to a relay to request admission. The event must have a claim tag that holds an invite code. The event's created_at must be now, plus or minus a few minutes.

Wire format - join request
{
  "kind": 28934,
  "pubkey": <user pubkey>,
  "tags": [
    ["-"],
    ["claim", <invite code>]
  ]
  // ...other fields
}

When a relay receives a claim, it must report the status of the claim in an OK message. Failed claims should use the standard restricted: prefix from NIP-42. On success, the relay should update its kind 13534 member list. It may also publish a kind 8000 add-user event.

OK responses to a claim
← ["OK", <event-id>, false, "restricted: that invite code is expired."]
← ["OK", <event-id>, false, "restricted: that is an invalid invite code."]
← ["OK", <event-id>, true, "duplicate: you are already a member of this relay."]
← ["OK", <event-id>, true, "info: welcome to wss://relay.bunk.skunk!"]
Tech Note

Two small gaps in the source. First, the join-request example carries the - tag, but the prose lists only claim as required. Second, the sample replies use info:, which is not a standard NIP-01 OK prefix.

6 Invite Request — Kind 28935

A user may ask a relay for a claim string. To do this, the user requests kind 28935 events with a normal NIP-01 REQ subscription. The relay answers with a kind 28935 event. That event must be signed with the NIP-11 self pubkey.

Wire format - invite
{
  "kind": 28935,
  "pubkey": <nip11.self>,
  "tags": [
    ["-"],
    ["claim", <invite code>]
  ]
  // ...other fields
}
Hint!

Kind 28935 sits in the ephemeral range, so relays store nothing. A relay must opt in and generate claims on the fly when a request arrives. This improves security: the relay can issue a different claim per request, issue claims only to certain users, or expire claims.

7 Leave Request — Kind 28936

A user may send a kind 28936 event to a relay to request that their access be revoked. The event must include the NIP-70 - tag. The event's created_at must be now, plus or minus a few minutes.

Wire format - leave request
{
  "kind": 28936,
  "tags": [["-"]]
  // ...other fields
}

On a leave request, the relay should update its kind 13534 member list. It may also publish a kind 8001 remove-user event.

8 Implementation Rule

Clients must check the relay's NIP-11 information document first. Only when supported_nips includes this NIP may a client request kind 28935 events from the relay or send kind 28934 events to it.

Client Relay ["REQ", "inv", {"kinds":[28935]}] ["EVENT", "inv", {kind 28935, claim}] ["EVENT", {kind 28934, ["claim", …]}] ["OK", <id>, true, "info: welcome!"] kind 13534 updated - kind 8000 published The user is now a member. Access policy is up to the relay.
Fig. 43-2 — Admission flow. Fetch an invite, send the claim, get an OK, appear in the member list.

9 Worked Example

The session below shows a full admission. Alice's client checks NIP-11 support out of band, fetches an invite, joins, and later leaves. Orange lines go to the relay. Blue lines come from the relay.

Session transcript - wss://club.example.com
-- 1. fetch an invite (relay supports NIP-43 per its NIP-11 document) --
→ ["REQ", "inv", {"kinds":[28935]}]
← ["EVENT", "inv", {"kind":28935, "pubkey":"a1b2c3d4…",
     "tags":[["-"],["claim","XK42-MEOW"]], …}]
← ["EOSE", "inv"]
→ ["CLOSE", "inv"]

-- 2. join with the claim --
→ ["EVENT", {"kind":28934, "pubkey":"c308e1f8…", "created_at":1782796800,
     "tags":[["-"],["claim","XK42-MEOW"]], "content":"", "sig":"…"}]
← ["OK", "7f31aa02…", true, "info: welcome to wss://club.example.com!"]

-- 3. the relay updates its metadata --
← ["EVENT", "meta", {"kind":8000, "pubkey":"a1b2c3d4…",
     "tags":[["-"],["p","c308e1f8…"]], …}]
← ["EVENT", "meta", {"kind":13534, "pubkey":"a1b2c3d4…",
     "tags":[["-"],["member","c308e1f8…"]], …}]

-- 4. months later, alice leaves --
→ ["EVENT", {"kind":28936, "pubkey":"c308e1f8…", "tags":[["-"]], …}]
← ["EVENT", "meta", {"kind":8001, "pubkey":"a1b2c3d4…",
     "tags":[["-"],["p","c308e1f8…"]], …}]

-- a failed claim looks like this --
← ["OK", "9c00d1ef…", false, "restricted: that invite code is expired."]

10 Version History

NIP-43 is young. It arrived in late 2025 and grew a role system half a year later. Notable changes, newest first:

  • 20262026-06Added role definitions (kind 33534). member tags in the membership list may now carry role ids as extra elements.
  • 20262026-06Reformatted the example blocks from jsonc to yaml across the repository.
  • 20252025-12Added the relay tag to the NIP's status line.
  • Origin2025-10hodlbod proposed relay access requests: membership lists, add/remove announcements, and the join, invite, and leave kinds.

Original Proposal - Credits

Authorhodlbod
First commit2025-10-30 — “Add relay access requests” (PR #1079)
Statusdraft - optional - relay — for relays with membership and their clients
Source43.md on GitHub - full change history

11 See Also

  • NIP-01 — the event object, REQ subscriptions, and OK messages used here.
  • NIP-11 — the relay information document; source of the self pubkey and supported_nips.
  • NIP-70 — protected events; defines the - tag required on every event in this NIP.
  • NIP-42 — client authentication; defines the restricted: prefix used for failed claims.