Moderation¶
Partly out of date
Rendered from ProjectInfo/client/moderation.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.
⚠️ Where this document and Encryption Modes disagree, that document wins. It reconciles the mode names, key distribution and media model across the specs and the running code, which have diverged. The CSAM report body documented here is not what the server implements and omits report verification entirely — see §6.
Roles¶
Roles control what server members can do. Each role is a permission bitfield. The @everyone role always exists and has id === server_id.
List roles¶
Fetch on server load. Cache per-server; invalidate on ROLE_UPDATE gateway event.
Create a role¶
POST /api/servers/{serverID}/roles
{
"name": "Moderator",
"color": 16711680, // 0xFF0000 = red (RGB packed integer)
"hoist": true, // show separately in member list
"mentionable": false,
"permissions": 8388608 // PermKickMembers = 1 << 22
}
→ 201 Role
Requires PermManageRoles.
Update a role¶
PATCH /api/servers/{serverID}/roles/{roleID}
{ "name": "string", "color": 0, "hoist": false, "mentionable": false, "permissions": 0 }
→ 200 Role
Delete a role¶
Assign a role to a member¶
Requires PermManageRoles.
Remove a role from a member¶
Channel Permission Overwrites¶
Override role permissions for a specific channel.
List overwrites¶
Set or replace an overwrite¶
PUT /api/channels/{channelID}/overwrites/{targetID}
{
"target_type": "role" | "member",
"allow": 0, // int64 bitfield — permissions to explicitly grant
"deny": 0 // int64 bitfield — permissions to explicitly deny
}
→ 200 PermissionOverwrite
targetID is a role ID or user ID. Bits not set in either allow or deny are inherited. Setting the same bit in both is undefined — deny takes precedence.
Remove an overwrite¶
Kicking Members¶
Requires PermKickMembers. Kicked members can rejoin via invite.
Banning Members¶
List bans¶
Requires PermBanMembers.
Ban a user¶
Banned users cannot use invites to rejoin (403 on invite accept).
Unban a user¶
Managing Messages¶
Delete a message¶
Requires PermManageMessages (to delete others' messages). Fires MESSAGE_DELETE.
Edit a message¶
PATCH /api/channels/{channelID}/messages/{messageID}
{ "content": "new content" }
→ 200 MessageResponse
Author only.
Message Reporting¶
Allow users to report inappropriate messages. The report modal should:
1. Show 7 reason chips (spam, harassment, NSFW, etc.)
2. Allow an optional detail text area
3. Show an encryption disclosure for rolling_key and peer_provided channels:
- "To investigate this report, your decryption key will be shared with our trust and safety team. This gives them the ability to read messages in this channel."
- This disclosure is required because the key must be included in the report for moderators to read the content.
POST /api/reports/message
{
"message_id": "uuid",
"channel_id": "uuid",
"reason": "harassment",
"detail": "optional free text"
}
→ 204
(Exact endpoint shape may vary; refer to server API docs.)
Reporting CSAM Attachments¶
If a user or the client-side scanner detects CSAM:
POST /api/reports/csam
{
"attachment_id": "uuid",
"evidence_note": "optional"
}
→ 201 { "report_id": "uuid" }
One report per attachment per user. Duplicate returns 409.
Permission Bits Quick Reference¶
| Constant | Value | Description |
|---|---|---|
PermViewChannel |
1 << 0 |
See channel + history |
PermSendMessages |
1 << 1 |
Post messages |
PermManageMessages |
1 << 3 |
Delete/pin others |
PermAttachFiles |
1 << 5 |
Upload files |
PermReadMessageHistory |
1 << 6 |
Load old messages |
PermMentionEveryone |
1 << 7 |
@everyone |
PermConnect |
1 << 10 |
Join voice |
PermSpeak |
1 << 11 |
Speak in voice |
PermMuteMembers |
1 << 12 |
Server-mute |
PermDeafenMembers |
1 << 13 |
Server-deafen |
PermMoveMembers |
1 << 14 |
Move in voice |
PermStream |
1 << 16 |
Screen share |
PermManageRoles |
1 << 19 |
Manage roles |
PermManageChannels |
1 << 20 |
Manage channels |
PermManageServer |
1 << 21 |
Server settings |
PermKickMembers |
1 << 22 |
Kick |
PermBanMembers |
1 << 23 |
Ban |
PermModerateMembers |
1 << 28 |
Timeout |
PermAdministrator |
1 << 29 |
Bypass all |
Server owner always has PermAdministrator regardless of role configuration.
Permission Resolution Algorithm¶
function resolvePermissions(
userId: string,
serverId: string,
channelId: string,
member: ServerMember,
roles: Role[],
overwrites: PermissionOverwrite[]
): number {
// Owner shortcut
if (server.owner_id === userId) return (1 << 29); // PermAdministrator
// 1. Start with @everyone (id === serverId)
const everyoneRole = roles.find(r => r.id === serverId)!;
let perms = everyoneRole.permissions;
// 2. OR in each role the member holds
for (const roleId of member.roles) {
const role = roles.find(r => r.id === roleId);
if (role) perms |= role.permissions;
}
// 3. Administrator short-circuit
if (perms & (1 << 29)) return (1 << 29);
// 4. Channel overwrites
const rolesWithEveryone = [serverId, ...member.roles];
for (const roleId of rolesWithEveryone) {
const ow = overwrites.find(o => o.target_id === roleId && o.target_type === "role");
if (ow) {
perms &= ~ow.deny;
perms |= ow.allow;
}
}
const memberOw = overwrites.find(o => o.target_id === userId && o.target_type === "member");
if (memberOw) {
perms &= ~memberOw.deny;
perms |= memberOw.allow;
}
return perms;
}
function hasPermission(perms: number, bit: number): boolean {
if (perms & (1 << 29)) return true; // Administrator
return (perms & bit) !== 0;
}