Room Messages
Endpoints for interacting with messages, typing indicators, and reactions within rooms.
Webhook messages: Messages sent via webhooks have
author_id: nullandwebhook_idset. Theuserfield in responses contains a synthetic user built from the webhook’s stored identity (webhook_author), withis_bot: true. Reply previews also resolve webhook author data automatically.
Get Message History
/api/rooms/{roomId}/messagesRetrieve paginated message history for a room.
Query Parameters
| Field | Type | Description |
|---|---|---|
count ? | integer | Number of messages to return |
before ? | uuid | Return messages before this message ID |
after ? | uuid | Return messages after this message ID |
order ? | string | Sort order (e.g. "asc" or "desc") |
Returns: Array of MessageResponse objects.
Get Message
/api/rooms/{roomId}/messages/{messageId}Retrieve a specific message in a room, including attachments and reactions.
Returns: MessageResponse object.
Get Message Thread
/api/rooms/{roomId}/messages/{messageId}/threadRetrieve the threaded replies for a specific room message. Each message includes a user object and webhook_id if applicable.
Each thread message includes a user object. For webhook messages (author_id is null), the user is built from the stored webhook_author data with is_bot=true. Thread messages also include ref_message_id for resolving reply chains within the thread.
The thread stays in the room it's read through: it only follows replies between messages of that room.
Returns: Array of ThreadMessageResponse objects.
Errors: 404 when the message isn't one of this room's.
Create Message
/api/rooms/{roomId}/messagesSend a new message to a room. Supports both JSON and multipart/form-data for file attachments. At least one of content, files, embeds, or sticker_attachment_id is required.
JSON Body
| Field | Type | Description |
|---|---|---|
content ? | string? | Message text content (max 5000 characters) |
nonce | string | Client-generated nonce for deduplication |
type | integer | Message type: 0 (a message) or 1 (a voice note); 2, a pin notice, is the API's only, and anything else is a 400 |
message_reference ? | MessageReference | The message this one replies to |
embeds ? | Embed[] | Array of embed objects |
sticker_attachment_id ? | string | The attachment_id of one of this room's space's stickers, to send it |
Message Reference Object
| Field | Type | Description |
|---|---|---|
type ? | integer | Reference type: 0 (reply), the only one |
message_id ? | string | Replied message ID |
room_id ? | string | Room of the replied message: this room (the default) |
space_id ? | string | Ignored: the reply stores this room's space |
fail_if_not_exists ? | boolean | Whether to fail if the referenced message does not exist |
Multipart Body
When sending files, use multipart/form-data:
| Field | Type | Description |
|---|---|---|
content ? | string | Message text content |
nonce | string | Client-generated nonce |
type ? | string | Message type (as string): 0 or 1, as in the JSON body |
message_reference ? | string | Message reference as JSON string |
files ? | file[] | Attachment files (not available for bots) |
sticker_attachment_id ? | string | As in the JSON body |
A message is sent with all its files or not at all: if one fails to upload, the message and the files already uploaded are deleted and the request fails.
Returns: MessageResponse object.
Errors: 400 with invalid message_reference: ... for a type other than 0 or an ID that isn't a UUID; 400 with invalid sticker_attachment_id when it isn't a UUID, or that sticker can't be sent here when it isn't the attachment_id of one of this space's stickers; 403 with replied message must be in the same room; 404 with referenced message not found, unless fail_if_not_exists is false (then the reply is sent without the reference); 413 for a file over your upload limit or the storage bucket's, or with no room left for it.
Update Message
/api/rooms/{roomId}/messages/{messageId}Update the content of a message. Only its author can edit it, and only while they can still see the room: someone who left the space can't.
JSON Body
| Field | Type | Description |
|---|---|---|
content | string | New message content (max 5000 characters) |
Returns: Message object.
Errors: 400 for a pin notice, which can't be edited.
Delete Message
/api/rooms/{roomId}/messages/{messageId}Delete a message from a room. Authors can delete their own messages; users with ManageMessages permission can delete others' messages, and pin notices (type 2), which their authors can't.
Returns: 204 No Content
Pinned Messages
A room has 250 pinned messages at most. Pinning a message posts the room’s pin notice for it, and pins and unpins reach members as MESSAGE_PIN_UPDATE.
Get Pinned Messages
/api/rooms/{roomId}/pinsList the room's pinned messages, the last pinned first. Requires ViewChannels.
Returns: Array of MessageResponse objects.
Pin Message
/api/rooms/{roomId}/pins/{messageId}Pin a message of the room, which posts the room's pin notice for it. Requires PinMessages. Pinning a pinned message changes nothing and posts no second notice.
Returns: 204 No Content
Errors: 400 for a pin notice, or when the room has 250 pinned messages already; 403 without PinMessages; 404 for a message that isn't in the room.
Unpin Message
/api/rooms/{roomId}/pins/{messageId}Unpin a message of the room. Requires PinMessages. Unpinning a message that isn't pinned changes nothing.
Returns: 204 No Content
Errors: 403 without PinMessages; 404 for a message that isn't in the room.
Typing & Read State
Send Typing Indicator
/api/rooms/{roomId}/typingNotify the room that the authenticated user is typing. Broadcasts a TYPING event via the gateway. Each user's notices go out at most once every 2 seconds per room: extra ones are still answered 204, and dropped.
Returns: 204 No Content
Send Recording Indicator
/api/rooms/{roomId}/recordingNotify the room that the authenticated user is recording a voice message. Broadcasts a RECORDING event via the gateway. It takes the same permissions as typing, and has its own limit: at most once every 2 seconds per room, extra ones answered 204 and dropped.
Returns: 204 No Content
Acknowledge Room
/api/rooms/{roomId}/ackMark the room as read for the authenticated user. Human-only. The read state only moves forward: an older message ID than the one stored leaves it as it is, so acks arriving out of order are harmless. A message_id that isn't a UUID is rejected (400).
JSON Body
| Field | Type | Description |
|---|---|---|
message_id | uuid | Newest message read in the room |
Returns: 204 No Content
Reactions
Add Reaction
/api/rooms/{roomId}/messages/{messageId}/reactionsAdd an emoji reaction to a room message.
JSON Body
| Field | Type | Description |
|---|---|---|
emoji_name | string | Unicode emoji character (e.g. "") or custom emoji UUID string |
emoji_id ? | uuid | Custom emoji attachment ID (for custom emojis only) |
Returns: 204 No Content
Errors: 404 when the message isn't one of this room's.
Remove Reaction
/api/rooms/{roomId}/messages/{messageId}/reactions/{emojiName}Remove your emoji reaction from a room message. The emojiName path parameter is the Unicode character or custom emoji UUID.
Returns: 204 No Content
Errors: 404 when the message isn't one of this room's.