Servers and Channels¶
Partly out of date
Rendered from ProjectInfo/client/servers-channels.md on docs/encryption-modes-spec. Its protocol content is still useful, but parts of it describe an older client or an earlier API. Where it disagrees with the code, the code wins — see the spec errata.
Servers¶
List joined servers¶
Create a server¶
The creating user becomes owner and first member.
Fetch one server¶
Update server settings¶
PATCH /api/servers/{serverID}
{
"name": "string",
"description": "string",
"icon_url": "/media/attachments/{id}",
"banner_url": "/media/attachments/{id}",
"verification_level": 0,
"explicit_filter": 0,
"afk_timeout_seconds": 300,
"system_channel_id": "uuid",
"rules_channel_id": "uuid",
"afk_channel_id": "uuid"
}
→ 200 Server
PermAdministrator.
Leave a server¶
Owner cannot leave — must delete the server or transfer ownership.Delete a server¶
Owner only. Permanent.Channels¶
List channels in a server¶
Sort by position ascending. Group by parent_id (category). Only show channels where PermViewChannel is satisfied.
Create a channel¶
POST /api/servers/{serverID}/channels
{
"name": "general",
"type": "text", // text | voice | announcement | stage | category
"topic": "optional",
"position": 0,
"nsfw": false,
"parent_id": "uuid", // optional category
"slowmode_seconds": 0,
"bitrate": 64000, // voice channels
"user_limit": 0, // voice; 0 = unlimited
"encryption_mode": "server_encrypted" // see below
}
→ 201 Channel
Requires PermManageChannels. encryption_mode cannot be changed after creation.
Encryption Modes¶
| Value | Server can read | History on join | Requires key setup |
|---|---|---|---|
server_encrypted |
Yes (disclosed) | Full history | No |
rolling_key |
No | None | Yes — create initial epoch immediately |
peer_provided |
No | None | Yes — deliver key P2P |
UI disclosure requirement: When creating a rolling_key or peer_provided channel, require the user to read and acknowledge that reporting encrypted messages will share the decryption key.
Voice channels always use server_encrypted regardless of the value passed.
Fetch a single channel¶
Edit a channel¶
PATCH /api/channels/{channelID}
{
"name": "new-name",
"topic": "string",
"position": 1,
"nsfw": false,
"slowmode_seconds": 10,
"parent_id": "uuid"
}
→ 200 Channel
PermManageChannels. encryption_mode cannot be changed.
Delete a channel¶
RequiresPermManageChannels.
Channel Read State¶
Track unread messages per channel.
Fetch read state¶
GET /api/channels/{channelID}/read-state
→ { channel_id, user_id, last_read_id, mention_count, updated_at }
Returns a zero-value struct if no row exists (not an error).
Acknowledge messages¶
Call when the user views a channel and reads the most recent message. The server updates mention_count to reflect unread @mentions since last_read_id.
Permission Resolution¶
Permissions are a bitfield. The server always re-validates, but the client must resolve permissions for UI rendering (show/hide channels, enable/disable inputs).
Algorithm¶
1. Start with @everyone role permissions
Note: @everyone role has id === server_id
2. OR in permissions from all roles the user holds
3. If Administrator bit is set → grant everything; stop
4. Apply channel permission overwrites in order:
a. @everyone overwrite: deny bits (AND NOT), then allow bits (OR)
b. Role overwrites (for each role user holds): deny then allow
c. Member overwrite: deny then allow
5. Server owner shortcut: if user is server owner → Administrator granted, skip all above
Permission Bits¶
| Constant | Bit | Description |
|---|---|---|
PermViewChannel |
1 << 0 |
See channel + read history |
PermSendMessages |
1 << 1 |
Post new messages |
PermSendTTSMessages |
1 << 2 |
Use /tts |
PermManageMessages |
1 << 3 |
Delete/pin others' messages |
PermEmbedLinks |
1 << 4 |
Auto-embed URLs |
PermAttachFiles |
1 << 5 |
Upload attachments |
PermReadMessageHistory |
1 << 6 |
Load old messages |
PermMentionEveryone |
1 << 7 |
@everyone / @here |
PermAddReactions |
1 << 8 |
React to messages |
PermConnect |
1 << 10 |
Join voice channel |
PermSpeak |
1 << 11 |
Speak in voice |
PermMuteMembers |
1 << 12 |
Server-mute others |
PermDeafenMembers |
1 << 13 |
Server-deafen others |
PermMoveMembers |
1 << 14 |
Move users between voice channels |
PermUseVAD |
1 << 15 |
Voice Activity Detection |
PermStream |
1 << 16 |
Screen share / stream |
PermChangeNickname |
1 << 17 |
Change own nickname |
PermManageNicknames |
1 << 18 |
Change others' nicknames |
PermManageRoles |
1 << 19 |
Create/edit/delete roles |
PermManageChannels |
1 << 20 |
Create/edit/delete channels |
PermManageServer |
1 << 21 |
Change server settings |
PermKickMembers |
1 << 22 |
Remove members |
PermBanMembers |
1 << 23 |
Ban members |
PermManageWebhooks |
1 << 24 |
Manage webhooks |
PermManageEmoji |
1 << 25 |
Custom emoji |
PermViewAuditLog |
1 << 26 |
View audit log |
PermViewServerInsights |
1 << 27 |
Analytics |
PermModerateMembers |
1 << 28 |
Timeout members |
PermAdministrator |
1 << 29 |
Bypass ALL checks |
Default @everyone Permissions¶
PermViewChannel | PermSendMessages | PermReadMessageHistory |
PermAddReactions | PermConnect | PermSpeak
Checking a Permission¶
function hasPermission(userPermissions: number, perm: number): boolean {
if (userPermissions & (1 << 29)) return true; // Administrator
return (userPermissions & perm) !== 0;
}
Invites¶
Create an invite¶
POST /api/servers/{serverID}/invites
{
"max_uses": 0, // 0 = unlimited
"expires_in": 86400 // seconds; 0 = never
}
→ 201 Invite
Preview an invite (no auth required)¶
Use this to show a server preview before the user decides to join.
Accept an invite¶
Invite link format: https://zipp.chat/join/{code}
Errors: 404 (expired/not found), 409 (already a member), 403 (banned)