Moderation, reports & audit log
OriginChats gives moderators tools to remove people, pause them, and keep pairs of users apart. It also filters messages automatically, collects reports from members, and records moderation actions in an audit log. This page explains how each piece behaves. The command pages hold the exact fields.
Tools at a glance
Section titled “Tools at a glance”| Tool | What it does | Who can use it |
|---|---|---|
| Ban | Removes a user and blocks them from signing in again. | manage_users |
| Kick | Disconnects a user. They can reconnect. | manage_users |
| Timeout | Blocks a user from posting and changing things for a set time. | manage_users |
| Sever | Hides two users from each other. | manage_users |
| Slow mode | Limits how often each user can post in a channel. | manage_channels |
| Automod | Blocks messages that match a word list and can time out the sender. | Server operator, through configuration |
| Reports | Lets members flag content for review. | Any member creates. review_reports reviews. |
| Audit log | Records who did what. | view_audit_log or manage_users |
Moderators can act through WebSocket commands or the built-in slash commands such as /ban, /mute, and /slow.
user_ban adds the banned role to the user and keeps their other roles. The server then:
- Closes all of the user’s connections after sending an auth rejection with the reason
You have been banned from this server. - Sends
user_leavewith the username to everyone connected. - Rejects the user’s future sign-ins.
The /ban slash command also takes a reason, and delete_messages: true deletes every message the user has posted. Each deleted message is broadcast as message_delete.
user_unban removes the banned role. The user can then sign in again.
user_kick closes all of the user’s connections with the reason Kicked: <reason>. It doesn’t change their roles, so they can reconnect straight away. Everyone else connected receives a user_kick event with the username.
Timeouts
Section titled “Timeouts”A timeout lets a user stay connected and read, but blocks them from changing anything. Set one with user_timeout or /mute, with a duration in seconds. A new timeout replaces the old one. /unmute clears it.
While a user is timed out, the server rejects commands that write, including:
- Sending, editing, deleting, and pinning messages, reacting, typing, and voting in polls.
- Creating or changing threads, running slash commands, joining voice, and unmuting in voice.
- Changing status, roles, channels, emoji, webhooks, plugins, or server settings, and filing reports.
- Uploading attachments or avatars, which fails with HTTP 429.
Reading history, searching, acknowledging unreads, leaving voice, muting in voice, and leaving the server still work.
A rejected command gets a rate_limit frame instead of an error. length is the time left in milliseconds, and src names the blocked command:
{ "cmd": "rate_limit", "src": "reaction_add", "reason": "You are in timeout for 12 more seconds", "length": 12000, "listener": "request-42"}The server also pushes rate_limit frames without a request:
- When a timeout starts, the user’s connections get one with the full length.
- When it ends or is cleared, they get one with
length: 0. Expiry sends the reasonYour timeout has expired.
Timeouts are saved to disk, so they survive a server restart. See the protocol model for how clients should handle these frames.
Severing
Section titled “Severing”Severing hides two users from each other without removing either from the server. A moderator with manage_users runs /sever with two usernames, and /unsever to undo it. Neither user can be the server owner. Both commands reply only to the moderator, and each is recorded in the audit log as user_sever or user_unsever.
Once two users are severed:
- Neither receives the other’s new messages as they’re sent.
- Neither sees the other’s messages when loading history, searching, or reading mention history.
- Replies to the other user lose their
reply_topreview, and the other user’s reactions are hidden. - Neither gets push notifications for the other’s messages.
- In voice, neither sees the other in the participant list. If both are in the same voice channel, each gets a
voice_user_leftfor the other. See severed users in voice.
Rotur bans
Section titled “Rotur bans”On servers that use Rotur accounts, the server checks every member against Rotur’s ban list 30 seconds after startup and then once an hour. A member whose Rotur account is banned is disconnected with the reason This Rotur account has been banned and removed from the member list. Everyone gets user_leave. This doesn’t add the banned role, so the server’s own ban list is unchanged.
Slow mode
Section titled “Slow mode”Slow mode makes each user wait a set number of seconds between messages in one channel. It applies to text channels and the chat in voice channels.
Set it with slow_mode_cooldown in channel_update, or with /slow <seconds> in the channel. Use 0 to turn it off.
The wait is counted from the user’s own last message in that channel. Only message_new is limited. A slowed message gets this frame instead of an error:
{ "cmd": "rate_limit", "reason": "Slow mode is active in this channel. Wait 4.2 more seconds before sending another message.", "length": 4200, "cooldown": 10, "last_message_timestamp": 1760000005.8, "listener": "send-17"}Channel objects include slow_mode_cooldown and last_message_by_user, so a client can show a countdown before the user tries to send.
The server owner, users with the admin role or the administrator permission, and users with manage_server skip slow mode.
Rate limits
Section titled “Rate limits”Apart from slow mode and timeouts, the OSL server limits only uploads. Each limit counts requests per user over a rolling 60 seconds:
| Upload | Limit | Response when exceeded |
|---|---|---|
| Attachments | attachments.uploads_per_minute, default 10 |
HTTP 429, Upload rate limit exceeded |
| Avatars | 5 | HTTP 429, Avatar upload rate limit exceeded |
Automod
Section titled “Automod”Automod checks message text against a list of blocked words and patterns before a message is saved. A match rejects the message, and it can also time out the sender. The server operator sets it up in the automod block of the server configuration, which also documents the rule file format. It’s off by default.
What automod checks
Section titled “What automod checks”Automod runs on:
- New messages from
message_new. - Edits from
message_edit. Only the fields in the edit are checked. - Replies that apps send with
slash_response. - Posts to incoming webhooks.
In each message it reads the text content, the alias name, attachment display names, and embed text. Embed text includes titles, descriptions, fields, author, footer, and provider names, media alt text and HTML, and poll questions and options. Before matching, it removes invisible formatting characters and collapses whitespace. URLs and signature fields aren’t checked.
Automod doesn’t check existing history, link previews, built-in slash command output, plugin or system messages, thread names, profile fields, or file contents.
What happens on a match
Section titled “What happens on a match”- The request fails with the error
Message blocked by automod. Nothing is saved or broadcast, and a poll in the message isn’t created. - If
timeout_secondsis above zero, the sender is timed out for that long. An automod timeout never shortens a longer timeout that’s already running. The server owner is never timed out. - The server records an
automod_blockentry in the audit log, with the channel and whether a timeout was applied. The blocked text isn’t recorded.
If the timeout can’t be saved, the message is still blocked and the error becomes Message blocked by automod; failed to save timeout.
Users who hold any role listed in bypass_roles skip automod. The default is ["owner"]. Administrators aren’t exempt unless one of their roles is on that list.
Webhooks and automod
Section titled “Webhooks and automod”A blocked webhook post returns HTTP 400 with {"error": "Message blocked by automod"}. Webhooks have no user account, so nobody is timed out.
For slash_response, automod checks the account of the app that sent the reply. A matching reply can time out that app’s account.
Reports
Section titled “Reports”Any member can flag content with report_create. A report targets a channel message, an attachment, or a user account. Messages inside threads can’t be reported, and a user report takes the account ID, not the username.
The server saves a snapshot of the content when the report is filed, so the report stays useful if the content is later edited or deleted. It keeps the newest 2000 reports.
A report moves from open to resolved or dismissed:
- A member files it. It starts as
open. - A reviewer with
review_reportsfinds it withreport_list, which lists the newest first and can filter by status. Reviewers aren’t notified when a report arrives, so poll this list. - The reviewer closes it with
report_resolve. The server records who closed it and when, and adds an audit log entry.
Hosted servers can also forward a report to the Rotur team with destination: "rotur". A forwarded report isn’t stored on the server. Other servers reject it with This server cannot forward reports to rotur.
Audit log
Section titled “Audit log”The audit log records moderation and management actions, such as bans, role changes, channel edits, setting changes, message deletions, and automod blocks. Read it with modlog_get, which can filter by category, actor, target, action, and time. modlog_summary counts entries by category and action. Both need view_audit_log or manage_users.
Each entry names the action, the actor, the target, and a details object specific to that action. Automated entries, such as automod blocks, use the actor name Automod.
Entries are grouped into categories, and each category has its own retention period, from 90 to 365 days by default. Old entries are removed the next time someone reads the log, so the log isn’t a permanent history. Operators can change the periods under modlog.retention, or stop recording with modlog.enabled: false. See categories and actions for the full list and the defaults.
