Messages
Messages live under their channel: /v1/channels/:channelId/messages. Content is stored as plain text with inline tokens (no HTML, no rich text); the client resolves tokens at render time.
The Message object
- Name
id- Type
- string
- Description
Snowflake.
- Name
channel_id- Type
- string
- Description
- Name
author_id- Type
- string
- Description
- Name
content- Type
- string
- Description
1–4000 chars. Plain text containing the inline token syntax.
- Name
edited_at- Type
- string | null
- Description
Independent timestamp so the UI can render an "edited" indicator without collapsing the row.
- Name
deleted_at- Type
- string | null
- Description
Soft delete. The row keeps its id so replies and references don't dangle; the UI renders a
[deleted]placeholder.
- Name
created_at- Type
- string
- Description
- Name
updated_at- Type
- string
- Description
Hydration fields the API attaches on the wire:
- Name
author- Type
- PublicUser
- Description
Embedded user row.
- Name
type- Type
- MessageType
- Description
- Name
attachments- Type
- Attachment[]
- Description
- Name
message_reference- Type
- { message_id, channel_id } | null
- Description
Reply target.
List messages
Keyset-paginated. No offset, no total — just the next page key.
- Name
limit- Type
- integer
- Description
1–100. Default 50.
- Name
before- Type
- string
- Description
Snowflake id. Returns messages strictly before this one, newest first.
Request
curl https://api.localuniverse.io/v1/channels/3123.../messages?limit=50 \
-H "authorization: <token>"
Create a message
- Name
content- Type
- string
- Description
1–4000 chars. May contain inline tokens.
- Name
nonce- Type
- ?string
- Description
Client-generated optimistic id. The server echoes it on the HTTP response and on the
MESSAGE_CREATEgateway dispatch so the author can reconcile its pending row with the canonicalmessage_id. Recipients with no matching pending row ignore it.
- Name
flags- Type
- ?integer
- Description
Bitfield.
- Name
message_reference_id- Type
- ?string
- Description
Id of the message this is replying to. Must live in the same channel.
Request
curl -X POST https://api.localuniverse.io/v1/channels/3123.../messages \
-H "authorization: <token>" \
-H "content-type: application/json" \
-d '{
"content": "hey <@312323...>, see <#9999...>",
"nonce": "9182374ab"
}'
The same payload is dispatched over the Gateway as MESSAGE_CREATE to every subscriber of the channel. See Gateway events.
Read, edit, delete
| Method | Path | Notes |
|---|---|---|
GET | /v1/channels/:channelId/messages/:messageId | Single message. |
PATCH | /v1/channels/:channelId/messages/:messageId | Edit content. Author only. Stamps edited_at. |
DELETE | /v1/channels/:channelId/messages/:messageId | Soft delete. Author can always delete; non-authors need channel.manage_messages. |
Inline tokens
User-authored text supports a small token syntax for entity references. The database stores raw tokens; the client resolves them at render time using local cache or fetches as needed.
| Token | Renders as |
|---|---|
<@USER_ID> | @display name, clickable |
<#CHANNEL_ID> | #channel name, linked |
<est:ESTIMATE_ID> | Linked estimate reference |
<item:ITEM_ID> | Linked item reference |
<t:UNIX_SECONDS> | Localized date/time |
<t:UNIX_SECONDS:STYLE> | Date/time formatted per style flag |
Timestamp styles:
| Style | Output |
|---|---|
d | 04/10/2026 |
D | April 10, 2026 |
t | 2:30 PM |
T | 2:30:00 PM |
f | April 10, 2026 2:30 PM (default) |
F | Saturday, April 10, 2026 2:30 PM |
R | 3 hours ago |
Markdown is supported alongside tokens (bold, italic, code, links, lists). Unknown or unresolvable tokens render as a plain-text fallback (e.g. @unknown) — clients should never raise on a missing entity.