HTTP API Reference
All API endpoints require an authenticated session unless noted otherwise.
Authentication is performed by the /login route, which sets a signed
session cookie. Subsequent requests include this cookie automatically.
All JSON responses use Content-Type: application/json.
Authentication
- GET /login
Render the login page.
- Response Headers:
Content-Type – text/html
- POST /login
Authenticate a user and establish a session.
- Form Parameters:
username – Account username.
password – Account password.
- Status Codes:
- Response Headers:
Set-Cookie –
session=<signed_value>on success.
Note
Failed login attempts are deliberately delayed by 3 seconds to slow brute-force attacks. Repeated failures additionally trigger account lockout: after
max_login_attemptsconsecutive failures an account is locked forlockout_duration_minutes(both configurable insettings.json).
- GET /logout
Log out the current user, set presence to offline, and clear the session.
Requires authentication.
- Status Codes:
302 Found – Redirect to
/login.
- GET /signup
Render the registration page.
- Response Headers:
Content-Type – text/html
- POST /signup
Register a new account.
- Form Parameters:
username – 1–32 characters; letters, numbers, hyphens, underscores. The reserved names
minimost,everyone, anddeleteduserare rejected (case-insensitively).password – Minimum 8 characters; must include uppercase, digit, and special character.
confirm_password – Must match
password.
- Status Codes:
Chat Interface
- GET /
Serve the main chat SPA.
Requires authentication.
- Response Headers:
Content-Type – text/html
Channels
- GET /channels
Return the list of public channel names.
Requires authentication.
- Response JSON Object:
channels (array) – Ordered list of channel name strings.
Example response:
["general", "software", "firmware", "off-topic"]
- GET /channel_unreads
Return unread message counts for every public channel.
Requires authentication.
- Response JSON Object:
object – Mapping of channel name to unread count.
Example response:
{"general": 3, "software": 0, "off-topic": 1}
Messages
- GET /messages/(channel)
Fetch messages for a channel since a given timestamp.
Requires authentication.
- Parameters:
channel – Public channel name or DM identifier (e.g.
dm:alice:bob).
- Query Parameters:
after (float) – Only return messages modified after this Unix timestamp. Defaults to
0(return all messages). PassNaNto also trigger a full load.
- Response JSON Object:
array – Array of message objects.
Message object fields:
Field
Type
Description
idinteger
Database primary key (shared message store).
channelstring
Channel or DM identifier.
senderstring
Username of the author.
contentstring or null
Message text body.
nullfor image-only messages.filenamestring or null
UUID-named image filename, served from
/files/<filename>.tsfloat
Unix timestamp (seconds).
editedinteger (0/1)
Whether the message has been edited.
edited_tsfloat or null
Timestamp of the most recent edit.
deletedinteger (0/1)
Soft-delete flag.
deleted_tsfloat or null
Timestamp of deletion.
reply_to_idinteger or null
ID of the parent message (shared message store).
reactionsstring (JSON) or null
JSON-encoded object mapping emoji names to lists of reactor usernames, e.g.
"{\"thumbs_up\": [\"alice\", \"bob\"]}"reactions_tsfloat or null
Timestamp of the most recent reaction change.
mentionsstring (JSON) or null
JSON-encoded array of the channel members
@-mentioned in the message, e.g."[\"alice\"]". The sentinel"@everyone"marks a channel-wide mention.nullwhen the message mentions no one. The client highlights the message and notifies the viewer when their username (or@everyone) appears here.
- POST /send/(channel)
Send a message and/or image attachment(s) to a channel.
Requires authentication.
Any
@usernametokens in text that resolve to real channel members are extracted (case-insensitively) and stored in the message’smentionscolumn;@everyoneis stored as the sentinel"@everyone". Tokens inside emails (foo@bar) and URLs are ignored.- Parameters:
channel – Target channel or DM identifier.
- Form Parameters:
text – Message text body (optional if files are provided).
reply_to_id – Integer ID of the parent message (optional).
files – One or more image files (multipart). Accepted extensions:
.jpg,.jpeg,.png,.gif,.webp.
- Status Codes:
200 OK – Returns the string
"ok".400 Bad Request – Empty message (no text and no valid files).
403 Forbidden – User is not permitted to post to the channel.
- GET /message/(msg_id)
Fetch a single message by ID.
Requires authentication.
- Parameters:
msg_id (int) – Message primary key.
- Response JSON Object:
id (integer) – Message ID.
sender (string) – Author’s username.
content (string) – Message text.
filename (string) – Image filename or null.
deleted (integer) – Soft-delete flag.
- Status Codes:
404 Not Found – Message not found.
- POST /edit/(msg_id)
Edit the text content of a message.
Requires authentication. Only the original sender can edit.
- Parameters:
msg_id (int) – Message ID.
- Form Parameters:
text – Replacement message text. Mentions are re-extracted from the new text and the
mentionscolumn is updated accordingly.
- Status Codes:
200 OK – Returns
"ok".403 Forbidden – Not the sender, or message not found.
- POST /delete/(msg_id)
Soft-delete a message.
Requires authentication. Only the original sender can delete.
- Parameters:
msg_id (int) – Message ID.
- Status Codes:
200 OK – Returns
"ok".403 Forbidden – Not the sender, or message not found.
- GET /search_messages
Search message history. The keyword is a case-insensitive substring match served by the trigram full-text index, so it stays fast regardless of history size. Results are confined to channels the caller may read (public channels, private channels they belong to, and their own DMs). At least one filter must be supplied; with none, an empty array is returned.
Requires authentication.
- Query Parameters:
q (string) – Search term (substring match).
from (string) – Restrict to a sender (case-insensitive).
channel (string) – Restrict to a single channel the caller can access.
start (float) – Only messages at or after this Unix timestamp.
end (float) – Only messages before this Unix timestamp.
- Response JSON Object:
array – Up to 50 matching message objects (fields:
id,channel,sender,content,ts), newest first.
Reactions
- POST /react/(msg_id)
Toggle an emoji reaction on a message.
Requires authentication.
- Parameters:
msg_id (int) – Message ID.
- Form Parameters:
reaction – Emoji name (e.g.
thumbsup,heart). Must be a valid reaction name from theVALID_REACTIONSset.
- Response JSON Object:
object – Current reactions map after the toggle, e.g.
{"thumbs_up": ["alice", "bob"]}
- Status Codes:
400 Bad Request – Invalid reaction name.
404 Not Found – Message not found.
Users and Presence
- GET /users
Return all registered users except the current user.
Requires authentication.
- Response JSON Object:
array – List of username strings.
- GET /channel_members/(channel)
Return the members of a channel that the current user may
@-mention, excluding the current user. For public channels this is every other registered user; for private channels the other members; for DMs the other participants. Used to populate the@-mention autocomplete dropdown.Requires authentication.
- Parameters:
channel – Channel name, DM identifier, or
private:<id>.
- Response JSON Object:
array – List of mentionable username strings.
- Status Codes:
403 Forbidden – User is not permitted to access the channel.
- GET /user_colors
Return the display name colour for every user that has set one.
Requires authentication.
- Response JSON Object:
object – Mapping of username to CSS hex colour string.
Example response:
{"alice": "#e06c75", "bob": "#61afef"}
- GET /user_avatars
Return the set of usernames that have a custom avatar.
Requires authentication.
- Response JSON Object:
array – List of username strings that have uploaded an avatar.
- GET /online_users
Return presence states for recently active users.
Requires authentication.
- Response JSON Object:
object – Mapping of username to presence state string (
"active","idle","hidden","offline").
Example response:
{"alice": "active", "bob": "idle", "charlie": "offline"}
- POST /presence
Update the current user’s presence state.
Requires authentication.
- Request JSON Object:
state (string) – One of
"active","idle","hidden","offline".
- Status Codes:
204 No Content – State updated.
- GET /typing/(channel)
Return users currently typing in a channel.
Requires authentication.
- Parameters:
channel – Channel or DM identifier.
- Response JSON Object:
array – List of username strings. Excludes the current user.
- POST /typing/(channel)
Report that the current user is typing.
Session is checked silently (not
@login_required).- Parameters:
channel – Channel or DM identifier.
- Status Codes:
204 No Content – Recorded.
Direct Messages
- GET /dms
Return a summary of all visible DM conversations.
Requires authentication.
Hidden conversations (closed by the user) are excluded unless a new message has arrived after the conversation was hidden.
- Response JSON Object:
array –
List of conversation objects, sorted by most recent activity. Each object has:
channel(string): DM channel identifier.users(array): Other participant usernames.unread(integer): Unread message count.
- POST /dms/close
Hide a DM conversation from the sidebar.
Requires authentication.
The conversation is not deleted. It reappears automatically when a new message is received after the hidden timestamp.
- Request JSON Object:
channel (string) – DM channel identifier to hide.
- Status Codes:
204 No Content – Conversation hidden.
400 Bad Request – Missing or invalid channel.
- GET /unread_count
Return the total number of unread DMs.
Requires authentication.
- Response JSON Object:
count (integer) – Total unread DM message count.
Read Receipts
- POST /mark_read/(channel)
Mark a channel as read by advancing the caller’s read watermark to its newest message.
Requires authentication.
- Parameters:
channel – Channel or DM identifier.
- Status Codes:
204 No Content – Watermark advanced.
- GET /read_receipts/(channel)
Return each member’s read watermark for a channel. A user has read a message iff their watermark is
>=that message’sts; the client derives the per-message✓indicators from the message timestamps it already holds. This keeps the payload proportional to the number of members, not the channel’s history length.Requires authentication.
- Parameters:
channel – Channel or DM identifier.
- Response JSON Object:
object – Mapping of each reader’s username to their read watermark (epoch seconds).
Example response:
{ "alice": 1716000001.456, "bob": 1716000000.123 }
User Settings
- GET /settings
Return the current user’s settings.
Requires authentication.
- Response JSON Object:
name_color (string) – CSS hex colour string, or
nullif not set.avatar_file (string) – Avatar filename, or
nullif not set.
- POST /settings
Update the current user’s settings.
Requires authentication.
- Form Parameters:
name_color – CSS hex colour in
#rrggbbformat (optional). Pass an empty string to clear the colour.
- Status Codes:
204 No Content – Settings saved.
400 Bad Request – Invalid colour format.
Avatars
- GET /avatar/(username)
Serve a user’s profile avatar image.
Requires authentication.
- Parameters:
username – Account username.
- Response Headers:
Content-Type –
image/jpeg
- Status Codes:
404 Not Found – User has no avatar.
- POST /avatar
Upload or replace the current user’s avatar.
Requires authentication.
The image should be pre-resized to 128 × 128 px by the client before upload (the frontend uses the Canvas API for this). The server stores the file as-is.
- Form Parameters:
avatar – Image file (
multipart/form-data). Accepted extensions:.jpg,.jpeg,.png,.gif,.webp.
- Status Codes:
204 No Content – Avatar saved.
400 Bad Request – No file provided or invalid file type.
- DELETE /avatar
Delete the current user’s avatar. The default initials avatar is shown to other users after removal.
Requires authentication.
- Status Codes:
204 No Content – Avatar removed.
Private Channels
- POST /private_channels/(channel_id)/leave
Leave a private channel.
Requires authentication.
A system message is posted to the channel notifying remaining members. If the leaving user is the last member, the channel is not automatically deleted — it becomes an empty room.
- Parameters:
channel_id – Private channel identifier (
private:<name>form).
- Status Codes:
204 No Content – User removed from channel.
403 Forbidden – User is not a member of the channel.
404 Not Found – Channel not found.
Files
- GET /files/(filename)
Serve an uploaded image file.
Requires authentication.
- Parameters:
filename – UUID-based image filename (as stored in the database).
- Response Headers:
Content-Type – Inferred from the file extension.
- Status Codes:
404 Not Found – File not found.
Link Previews
- GET /link_preview
Fetch a link preview card for a URL.
Requires authentication.
- Query Parameters:
url (string) – Fully-qualified URL to preview.
- Response JSON Object:
object – Preview data. Shape depends on the type:
Code preview (Bitbucket):
{ "type": "code", "filename": "chat.py", "filepath": "src/minimost/chat.py", "language": "py", "first_line_num": 1, "highlight_start": 50, "highlight_end": 60, "code": "...", "total_lines": 616, "url": "https://bitbucket.org/..." }
OpenGraph preview:
{ "type": "og", "title": "Page Title", "description": "Page description...", "image": "https://example.com/image.png", "domain": "example.com", "url": "https://example.com/page" }
No preview available:
{}