HTTP & uploads
The HTTP server and WebSocket share the configured port. CORS and WebSocket origins are currently open; authentication and authorization happen at the application layer.
Routes
Section titled “Routes”| Method | Path | Purpose |
|---|---|---|
GET |
/, /info, /user/{username} |
Rendered public pages |
GET |
/server-assets/{name} |
Resolved server icon/banner |
GET |
/emojis/{name} |
Custom emoji content |
GET |
/stickers/{name} |
Custom sticker content |
POST |
/attachments/upload |
Attachment upload |
GET |
/attachments/{id} |
Attachment download/redirect |
GET |
/webhooks[/path…] |
Webhook information/verification |
POST |
/webhooks[/path…] |
Receive a webhook payload |
Attachment lifecycle
Section titled “Attachment lifecycle”- Read
handshake.val.attachments. Ifenabledis false, do not show uploads. - Enforce
max_size, MIMEallowed_types, account quota, requested expiry, and configured upload rate client-side for fast feedback. Do not rely on the handshake’s hard-codeduploads_per_minute: 10when an operator may have changedattachments.uploads_per_minute. - Obtain a Rotur validator for the supplied
validator_key, then include both values in the upload body. This is separate from the WebSocket connection’s authentication state. - Use the returned attachment reference in
message_new.attachments. - The message handler resolves references to trusted attachment objects before persistence.
The server accepts local or S3-compatible storage. Although compression settings are defined, the current upload path stores the decoded bytes without resizing or recompressing them. A deleted message triggers deletion of its referenced attachments.
The handshake reports uploads.uploads_per_minute: 10 as a fixed value. Actual upload enforcement reads attachments.uploads_per_minute, so clients should treat an upload rejection as authoritative when an operator has configured a different limit.
Upload bodies
Section titled “Upload bodies”JSON uploads use file (base64 or an exact data:<mime_type>;base64,… URI), name, mime_type, validator_key, validator, and optional expires_in_days. Multipart uploads use the same names with a file part named file. File names must be 1–255 characters with no CR/LF. expires_in_days must be positive; it is capped by free_tier_max_expiration_days (default seven). When that cap is -1, stored uploads have no expiry. Every current upload response has permanent: false.
Asset URLs
Section titled “Asset URLs”Server icon and banner values are resolved through the asset backend at startup. Custom emoji and sticker records point at their content endpoint. Clients should use the URLs returned by server objects instead of deriving filesystem paths.
