Messaging
In-system chat for your account: spaces contain categories and channels; channels hold messages with optional attachments, GIFs, replies, mentions, and link previews.
Base path: /api/v1/messaging. Read (GET) needs messaging: read. Write (POST, PATCH, PUT, DELETE) needs messaging: read_write. See Authentication and Scopes.
Message bodies are encrypted at rest. List, send, and edit endpoints decrypt server-side and return a content string.
After send or edit, link preview fetching runs in the background (not blocking the HTTP response).
Layout
Space
├── Category (optional grouping)
│ └── Channel (text | media)
└── Channel (uncategorised)
Message → channel
Attachment → staged upload → referenced in send bodyStart with bootstrap for the full tree plus unread counts, or list spaces/channels individually.
Endpoint index
| Method | Path | Scope |
|---|---|---|
| GET | /messaging/bootstrap | read |
| GET/POST | /messaging/spaces | read / read_write |
| PATCH/DELETE | /messaging/spaces/{spaceId} | read_write |
| POST | /messaging/spaces/reorder | read_write |
| POST | /messaging/spaces/icon/upload-intent, …/complete | read_write |
| GET/POST | /messaging/spaces/{spaceId}/categories | read / read_write |
| POST | …/categories/reorder | read_write |
| PATCH/DELETE | /messaging/categories/{categoryId} | read_write |
| PATCH | /messaging/categories/{categoryId}/collapsed | read_write |
| GET/POST | /messaging/spaces/{spaceId}/channels | read / read_write |
| POST | …/channels/reorder | read_write |
| PATCH/DELETE | /messaging/channels/{channelId} | read_write (DELETE archives) |
| PATCH | /messaging/channels/{channelId}/move | read_write |
| GET/POST | /messaging/channels/{channelId}/messages | read / read_write |
| GET | …/messages/newer, …/messages/around | read |
| PATCH/DELETE | /messaging/messages/{messageId} | read_write |
| GET/POST | /messaging/channels/{channelId}/pins | read / read_write |
| DELETE | …/pins/{messageId} | read_write |
| POST | /messaging/channels/{channelId}/read | read_write |
| POST | /messaging/attachments/upload-intent, …/complete | read_write |
| GET | /messaging/attachments/{attachmentId}/access-url | read |
| POST | /messaging/link-previews/{previewId}/dismiss, …/refresh | read_write |
| GET/PUT | /messaging/preferences/chat-as, …/last-viewed-route, …/emoji, …/gif | read / read_write |
| GET | /messaging/preferences/chat-as-members | read |
| GET | /messaging/gifs/search, …/browse, …/categories | read |
| GET | /messaging/mentions?channelId=… | read |
All paths are prefixed with /api/v1.
Bootstrap
GET/api/v1/messaging/bootstrap
Single call for spaces, categories, channels, per-channel unread counts, and last visited space/channel ids. Space rows may include a resolved iconUrl.
{
"spaces": [{ "id": "…", "name": "General", "iconUrl": null }],
"categories": [{ "id": "…", "spaceId": "…", "name": "Text", "collapsed": false }],
"channels": [{ "id": "…", "spaceId": "…", "categoryId": null, "name": "lobby", "channelType": "text" }],
"unreadByChannelId": { "channel-uuid": 3 },
"lastSpaceId": "space-uuid",
"lastChannelId": "channel-uuid"
}curl -sS \
-H "Authorization: Bearer YOUR_TOKEN" \
"https://api.floralitys.com/api/v1/messaging/bootstrap"Spaces
GET/api/v1/messaging/spaces: list spaces.
POST/api/v1/messaging/spaces: create. Body: name (required), optional description, iconStorageRef, iconStagingId (after icon upload flow), sideSystemId (tie to a side system). Returns 201.
PATCH/api/v1/messaging/spaces/{spaceId}: update name, description, icon.
DELETE/api/v1/messaging/spaces/{spaceId}: archives the space (soft delete). 204.
POST/api/v1/messaging/spaces/reorder: body { "orderedSpaceIds": ["uuid", …] }.
Space icon upload
- POST /messaging/spaces/icon/upload-intent: body { contentType, byteSize } → presigned upload + stagingId
- Upload bytes to the presigned URL client-side
- POST /messaging/spaces/icon/complete: body { stagingId }
- Pass iconStagingId on space create/update
Categories
GET/api/v1/messaging/spaces/{spaceId}/categories
POSTsame path: body { "name" } (1–80 chars).
POST…/categories/reorder: body { "orderedCategoryIds": […] }.
PATCH/api/v1/messaging/categories/{categoryId}: rename.
PATCH/api/v1/messaging/categories/{categoryId}/collapsed: body { "collapsed": true }.
DELETE/api/v1/messaging/categories/{categoryId}: remove category.
Channels
GET/api/v1/messaging/spaces/{spaceId}/channels
POSTsame path: body:
name(required)categoryId: optional;nullfor uncategorisedtopic: optional channel topicchannelType:text(default) ormedia
PATCH/api/v1/messaging/channels/{channelId}: update name/topic.
PATCH/api/v1/messaging/channels/{channelId}/move: body { "categoryId": "uuid" | null }.
POST…/channels/reorder: body { "orderedChannelIds": […] } within the space.
DELETE/api/v1/messaging/channels/{channelId}: archives channel. 204.
List messages (older)
GET/api/v1/messaging/channels/{channelId}/messages
Query
| Param | Notes |
|---|---|
limit | 1–150, default 50 |
beforeCreatedAt + beforeId | Cursor from previous nextCursor (paginate backward in time) |
Response
200: page with items, nextCursor, and pinnedMessageIds for messages in this page.
{
"items": [
{
"id": "msg-uuid",
"channelId": "channel-uuid",
"authorMemberId": "member-uuid",
"content": "Decrypted plaintext for API consumers",
"createdAt": 1714237200000,
"editedAt": null,
"attachments": [],
"linkPreviews": [],
"mentions": [],
"replyTo": null,
"authorMemberAvatarUrl": "/api/v1/members/…/media?kind=avatar&v=…"
}
],
"nextCursor": { "beforeCreatedAt": 1714237000000, "beforeId": "older-msg-uuid" },
"pinnedMessageIds": ["pinned-msg-uuid"]
}curl -sS \
-H "Authorization: Bearer YOUR_TOKEN" \
"https://api.floralitys.com/api/v1/messaging/channels/CHANNEL_ID/messages?limit=50"List newer messages
GET/api/v1/messaging/channels/{channelId}/messages/newer
Required query: afterCreatedAt, afterId. Optional limit. Use after realtime updates or polling.
Messages around anchor
GET/api/v1/messaging/channels/{channelId}/messages/around
Query: anchorMessageId (required), optional beforeLimit / afterLimit (each 1–100). Jump-to-message in clients.
Send message
POST/api/v1/messaging/channels/{channelId}/messages
Request body
| Field | Required | Notes |
|---|---|---|
memberId | yes | Member posting as (chat identity) |
content | no | Max 4000 chars; omit or null for attachment/GIF-only |
replyToMessageId | no | Thread reply |
gifMetadata | no | GIF picker payload (see gif preferences) |
stagedAttachmentIds | no | UUIDs from completed attachment upload flow |
clientMutationId | no | Idempotency hint for clients (max 100 chars) |
Response
201: full decrypted message object. Link previews populate asynchronously.
{
"id": "msg-uuid",
"channelId": "channel-uuid",
"content": "Hello from the API",
"createdAt": 1714237200000
}curl -sS -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"memberId":"MEMBER_UUID","content":"Hello from the API"}' \
"https://api.floralitys.com/api/v1/messaging/channels/CHANNEL_ID/messages"Edit and delete message
PATCH/api/v1/messaging/messages/{messageId}: body { "content": "…" } (max 4000). Returns updated message.
DELETE/api/v1/messaging/messages/{messageId}: soft-delete. 204.
Pins
List, add, and remove pinned messages in a channel.
POSTsame path: body { "messageId": "uuid" }.
DELETE/api/v1/messaging/channels/{channelId}/pins/{messageId}
Mark channel read
POST/api/v1/messaging/channels/{channelId}/read
Body: optional lastReadMessageId. Clears unread for the channel. 204.
Attachments
Two-step upload, then reference in send.
- POST /api/v1/messaging/attachments/upload-intent: body: channelId, fileName, contentType, byteSize, optional width, height, durationMs. Returns presign + stagingId (201).
- PUT bytes to presigned URL
- POST /api/v1/messaging/attachments/complete: body { stagingId } → 204
- Include stagedAttachmentIds in send message
GET/api/v1/messaging/attachments/{attachmentId}/access-url: short-lived download URL JSON for an attachment you own.
Link previews
Previews attach to messages after send/edit. To dismiss or refresh a stale card:
POST /api/v1/messaging/link-previews/{previewId}/dismissPOST /api/v1/messaging/link-previews/{previewId}/refresh
Both return 204.
Preferences
| Method | Path | Purpose |
|---|---|---|
| GET/PUT | /messaging/preferences/chat-as | GET query spaceId, optional channelId. PUT body: spaceId, channelId?, memberId. |
| GET | /messaging/preferences/chat-as-members | Members you can post as |
| PUT | /messaging/preferences/last-viewed-route | Body { lastSpaceId, lastChannelId } (nullable UUIDs) |
| GET/PUT | /messaging/preferences/emoji | Emoji picker settings (v1 schema) |
| GET/PUT | /messaging/preferences/gif | GIF provider preferences + content filter |
GIF search
Read-only proxy to the configured GIF provider (requires server keys):
GET /messaging/gifs/search?query=…&limit=&cursor=&contentFilter=&locale=GET /messaging/gifs/browse?query=&categoryId=&limit=&cursor=GET /messaging/gifs/categories
Pass returned metadata in gifMetadata when sending.
Mentions autocomplete
GET/api/v1/messaging/mentions
Query: channelId (required), optional query (max 40 chars), limit (1–15). Returns members mentionable in that channel for @-autocomplete.
Errors
Failures return { code, message }. Common: UNAUTHORIZED (401), FORBIDDEN (403), NOT_FOUND (404), BAD_REQUEST (400). See Errors.
{
"code": "NOT_FOUND",
"message": "Channel not found."
}// 204 No Content: empty response body