Wikifreedia
All versions

Rooms inside a Community are named spaces with their own title, description, optional per-room services (e.g. LiveKit), and profile lists that gate who may post in that room only. Lists are kind 30000 events referenced by a on kind:30223. Communities using rooms MUST not put a tags on the Rooms row of kind 10222 — see Rooms in Community. 30223 is the sole source of truth for room posting ACL.

Tag usage on kind 9 and 30223 is chosen so NIP-29 (Group) kind 9 events can be copied onto a community relay with minimal edits: NIP-29 already puts the group id in h. Here h keeps that role — an opaque room id, not a display name. The community pubkey is carried in c, which NIP-29 chat events lack until you add it when migrating.

Community room definition (kind:30223)

A parameterized replaceable event (NIP-33): the community key (same pubkey as kind 10222) publishes one current definition per room. The d tag is the room id on the wire — the same string as h on kind 9 messages in that room.

Room id (wire) vs display name

The room id (d on 30223, h on kind 9) is an opaque identifier. It SHOULD be random (or otherwise unique) and use only a-z, 0-9, -, _, matching NIP-29 group id rules (Group). Relays and clients that index or enforce by room MUST use this value — e.g. #h on kind 9 for the room bucket on an enforcing relay.

The human-readable title (“Dev chat”, “General”, etc.) lives only in the name tag (and prose in content) on 30223. Do not use the display name as the wire id; do not treat h/d as a slugified title unless you deliberately choose that (it breaks the NIP-29 migration story and collision safety).

Within one community, each d is unique among that community’s 30223 events. Globally, (c, d) identifies a room — c is the community pubkey on 30223 (see below).

Required tags

Tag Description
d Opaque room id — same value as h on kind 9 in this room (Room id).
c Community pubkey (hex) — MUST match the event author (same as c on kind 9 messages).
a Profile list reference: 30000:<pubkey>:<d> — same as on kind 10222. Include one a tag per profile list that applies to this room (see Who may post).

Optional tags

Tag Description
name Human-readable title for clients (not the wire id).
image Room image URL (avatar or banner).
livekit Per-room realtime server URL. If absent, clients MAY fall back to community livekit on kind 10222.
other Future service tags; clients SHOULD ignore unknown tags.

Event structure

{
  "kind": 30223,
  "pubkey": "<community-pubkey>",
  "created_at": 1675642635,
  "tags": [
    ["d", "<opaque-room-id>"],
    ["c", "<community-pubkey>"],
    ["a", "30000:<pubkey>:<list-d>", "<relay-url>"],
    ["name", "<human-readable title>"],
    // ["image", "<url>"],
    // ["livekit", "<url>"]
  ],
  "content": "<long description — markdown or plain text>"
}

Who may post in a room

Profile lists (kind 30000) are standalone events. For room-based chat, posting permission is defined only on kind:30223:

  • One or more a tags (required): an author MAY post if their pubkey is a p tag on at least one of the referenced lists (OR across lists). Clients fetch each 30000:<pubkey>:<d> and check membership.
  • Clients MUST not fall back to a tags on the Rooms row of kind 10222 for kind 9 messages in a room (Community Rooms).

Rooms do not define new join flows: lists still use optional form tags, admin edits p tags, etc., per Profile List.

Room-scoped chat (kind:9)

Messages in a room are kind 9 with:

  • h — opaque room id (same string as d on that room’s 30223).
  • ccommunity pubkey (hex).

Together (c, h) selects exactly one room. This mirrors NIP-29’s h = group id; c scopes the message to your community.

Kind 9 events with h but no c are outside this spec (e.g. plain NIP-29 or legacy shapes) — see Community.

Relay monitors use c for other meanings on other kinds (Relay Discovery). For kind 9, c here is a 64-hex pubkey; still use kinds: [9] (and #c / #h as needed) so monitor events do not mix in.

Required tags

Tag Description
h Opaque room id — NIP-29 group id compatible; equals d on 30223.
c Community pubkey (hex).

Event structure

{
  "kind": 9,
  "pubkey": "<author-pubkey>",
  "created_at": 1675642635,
  "tags": [
    ["h", "<opaque-room-id>"],
    ["c", "<community-pubkey>"]
  ],
  "content": "<message>"
}

Use at most one h and at most one c for this shape. Duplicates are undefined (clients SHOULD reject or apply one rule).

NIP-29 migration

Existing NIP-29 kind 9 events already have h = group id. To adopt this community model:

  1. Keep h unchanged (same opaque id).
  2. Add c = your community’s pubkey (hex).
  3. Publish 30223 with d = that same id, c = community pubkey (author), a lists, and name (and optional content) for the human-facing title and description.

After that, enforcing relays can bucket by #h like NIP-29, while scoping to a community via #c.

Client recommendations

  • For subscriptions: kinds: [9], #c = community pubkey, #h = room id when following one room.
  • Resolve 30223 by community author + d = message h, and c matching the message’s community; enforce Who may post from that event’s a tags only.
  • MAY show name from 30223 in UI; on the wire, identity is (c, h), not the title.
  • Discover rooms: kind 30223 by author = community; each event’s d / name / a describe one room.

Examples

Example: room definition

{
  "kind": 30223,
  "pubkey": "3bf0c63fcb93463407fd977870e7a68c66f8868576d639e220416298702c834e",
  "created_at": 1735689600,
  "tags": [
    ["d", "k7m2p9xq1n"],
    ["c", "3bf0c63fcb93463407fd977870e7a68c66f8868576d639e220416298702c834e"],
    ["name", "Dev chat"],
    ["a", "30000:3bf0c63fcb93463407fd977870e7a68c66f8868576d639e220416298702c834e:dev-chat-posters", "wss://relay.example.com"],
    ["livekit", "wss://live.example.com/room-dev"]
  ],
  "content": "Engineering discussion. Be kind."
}

d is opaque; “Dev chat” is only in name.

Example: message in that room

{
  "kind": 9,
  "pubkey": "97fa5b5c8b3e4c2d1a0f9e8d7c6b5a4938271605f4e3d2c1b0a97867564534231",
  "created_at": 1735689700,
  "tags": [
    ["h", "k7m2p9xq1n"],
    ["c", "3bf0c63fcb93463407fd977870e7a68c66f8868576d639e220416298702c834e"]
  ],
  "content": "Shipped the relay fix — can someone test?"
}

See Also

  • CommunityRooms on kind 10222 uses k 30223 (not 9), no a on that row; h on other kinds = community pubkey
  • Group — NIP-29 h = group id (same wire shape as our room id)
  • Profile List — kind 30000, p / form / list identity