Skip to main content
The chat module is the server-side client for Sublay’s messaging: direct and group conversations, messages (with GIFs, mentions, threads, quotes, and file attachments), membership, reactions, read state, and reporting.

Acting on behalf of a user

Your service key has no implicit session user, so every chat call takes the user it acts as. Most functions take that user as userId; the few where userId already names a target take the actor as actingUserId instead (createDirectConversation, addMember, removeMember, changeMemberRole).
Membership is enforced against the acting user (resolve-then-check). Sublay resolves the named user first, then runs the normal conversation checks against that user. So you can only act as a user who is genuinely a member of the conversation, and admin-only actions (delete/update conversation, add/remove members, change roles) require that user to be a group admin. A service key cannot post into a conversation as a user who isn’t in it.
Naming a user other than the caller’s own is gated to service/master keys. With a service key, omitting the acting user returns 400 chat/missing-user-id.

Conversations

listConversations

Lists the acting user’s conversations, newest activity first. Uses cursor (keyset) pagination — pass the last item’s lastMessageAt as cursor and its createdAt as cursorCreatedAt to get the next page.
string
required
The user whose conversations are listed.
string
Comma-separated filter: any of direct, group, space.
string
Keyset cursor — the lastMessageAt of the last item from the previous page.
string
Tie-breaker cursor — the createdAt of the last item from the previous page.
number
Page size, 1–50. Defaults to 20.
Returns — Promise<{ conversations: ConversationPreview[]; hasMore: boolean }> Each ConversationPreview includes otherMembers — up to 5 active members other than the acting user (id, name, username, avatar) for direct/group conversations, so a DM/group can render the counterparty without a separate members fetch. Capped at 5 (use memberCount for the group total); empty for space conversations.

createDirectConversation

Creates (or returns the existing) one-to-one conversation between the acting user and a target user.
string
required
The other participant (the target).
string
required
The user initiating the DM.
Returns — Promise<Conversation>

createGroupConversation

Creates a group conversation; the acting user becomes its admin.
string
required
The acting user (becomes the group admin).
string
Group name.
string
Group description.
string[]
Initial members to add.
object
Custom key-value data.
Returns — Promise<Conversation>

getConversation

Fetches a single conversation the acting user is a member of.
string
required
string
required
The acting user (must be a member).
Returns — Promise<Conversation>

updateConversation

Updates a group conversation. Requires the acting user to be a group admin.
string
required
string
required
The acting user (must be a group admin).
string
string
string | null
File id for the avatar, or null to clear it.
"members" | "admins"
Space conversations only.
Returns — Promise<Conversation>

deleteConversation

Deletes a group conversation. Requires the acting user to be a group admin.
string
required
string
required
The acting user (must be a group admin).
Returns — Promise<void>

getUnreadCount

Returns the acting user’s unread totals across all conversations.
string
required
Returns — Promise<{ totalUnread: number; unreadConversationCount: number }>

Members

listMembers

string
required
string
required
The acting user (must be a member).
number
Defaults to 1.
number
1–100, defaults to 50.
"admin" | "member"
Filter by role.
Returns — Promise<PaginatedResponse<ConversationMember>>

addMember

Adds a member to a group. Requires the acting caller to be a group admin.
string
required
string
required
The member to add (the target).
string
required
The caller (must be a group admin).
Returns — Promise<ConversationMember>

removeMember

Removes a member from a group. Requires the acting caller to be a group admin.
string
required
string
required
The member to remove (the target).
string
required
The caller (must be a group admin).
Returns — Promise<void>

changeMemberRole

Promotes or demotes a member. Requires the acting caller to be a group admin.
string
required
string
required
The member whose role changes (the target).
"admin" | "member"
required
string
required
The caller (must be a group admin).
Returns — Promise<ConversationMember>

leaveConversation

string
required
string
required
The user leaving.
Returns — Promise<void>

Messages

listMessages

Lists messages in a conversation. Uses cursor pagination — pass before (an ISO timestamp) to page backwards, or after to page forwards (before/after are mutually exclusive).
string
required
string
required
The acting user (must be a member).
string
Restrict to replies of this message (thread view).
string
ISO timestamp — messages created before this. Mutually exclusive with after.
string
ISO timestamp — messages created after this. Mutually exclusive with before.
number
1–100, defaults to 50.
"asc" | "desc"
string
Comma-separated associations to populate: "files" (message attachments) and "grants" (each message’s reputation-grant summary). Combine them as "files,grants".
MessageFilters
Optional filters. filters.hasReplies (boolean): when true, returns only messages that have thread replies (threadReplyCount > 0); when false, only messages with none. Filters by thread replies, not quotings. Threads are one level deep, so hasReplies: true together with parentId always returns an empty list — the response’s notice field explains why.
Returns — Promise<{ messages: ChatMessage[]; hasMore: boolean; oldestCreatedAt: string | null; newestCreatedAt: string | null }>

sendMessage

Sends a message as the acting user. A message must have content, a GIF, or at least one file. When files are attached the request is sent as multipart/form-data; otherwise it’s a JSON body.
string
required
string
required
The message author (must be a member).
string
Up to 4000 characters.
GifData | null
An attached GIF object.
Mention[]
User/space mentions.
string
Reply within a thread.
string
Quote another message.
object
Custom key-value data.
string
Client-generated id echoed back on the created message (not stored).
ChatMessageFile[]
Attachments: { file: Uint8Array | Blob; filename?: string; mimeType?: string }[], up to 10.
Returns — Promise<ChatMessage>

getMessage

string
required
string
required
string
required
The acting user (must be a member).
string
Comma-separated associations to populate. Only "grants" is supported here — it attaches the message’s reputation-grant summary at message.grants.
Returns — Promise<ChatMessage>

editMessage

Edits a message. Requires the acting user to be the message author.
string
required
string
required
string
required
The acting user (must be the message author).
string
GifData | null
A GifData attachment, or null to clear it.
Mention[]
object | null
Returns — Promise<ChatMessage>

deleteMessage

Soft-deletes a message. Requires the acting user to be the author or a group admin.
string
required
string
required
string
required
The acting user (author or group admin).
Returns — Promise<void>

Reporting a message

Message reports go through the shared reports API, not a chat-specific function — the same call that reports entities and comments.
targetId is the message id; the conversation is resolved server-side, so no conversationId is needed. The reporter must be a member of the conversation and cannot report their own message. See createReport.

Reactions

toggleReaction

Adds or removes the acting user’s emoji reaction on a message.
string
required
string
required
string
required
string
required
The reacting user (must be a member).
Returns — Promise<{ reactionCounts: Record<string, number>; userReactions: string[]; delta: 1 | -1 }> (delta is 1 if the reaction was added, -1 if removed).

listReactions

Lists the users who reacted with a given emoji.
string
required
string
required
string
required
The emoji to list reactors for.
string
required
The acting user (must be a member).
number
Defaults to 1.
number
1–100, defaults to 50.
Returns — Promise<{ data: MessageReaction[]; pagination: { page; limit; total; hasMore } }>

Read state

markAsRead

Marks the conversation read up to a given message.
string
required
string
required
The message up to which the conversation is marked read.
string
required
The acting user (must be a member).
Returns — Promise<void>

muteConversation

Sets or clears a user’s mute on a conversation. Muting suppresses the message push for this conversation only; the message is still delivered. See Notification Preferences & Mute.
Like every other chat call, the Node SDK names the acting user with userId (the service key acts on that user’s behalf). The user must be a member of the conversation, and the returned currentMember is that user’s own row. End-user-token clients (the React hooks, the browser JS SDK) act on the signed-in user and omit userId.
string
required
"8h" | "24h" | "1w" | "forever" | null
required
The mute duration choice, or null to clear the mute. Send the choice, never a raw timestamp.
string
required
The user whose mute is set (must be a member).
Returns — Promise<{ currentMember: ConversationMember }> — that user’s own member row.
“Forever” is an explicit signal. A forever mute returns mutedForever: true with mutedUntil: null. A timed mute returns mutedForever: false with a real ISO mutedUntil. Read the boolean — never string-match a far-future date.

Space conversations

Each space has a single built-in conversation. These three live on client.spaces (they’re /spaces/... routes), not on client.chat.

spaces.getSpaceConversation

Fetches-or-creates a space’s conversation and joins the acting user to it. The acting user must be an active member of the space; a pending or rejected request, or a ban, is refused.
string
required
string
required
The acting user (must be an active member of the space).
Returns — Promise<Conversation>

spaces.moderateSpaceChatMessage

Removes a message in a space conversation.
On the two space-chat moderation routes, actingUserId is optional. Omit it and your service key acts as the project, passing the space-moderator check. Name a user and the request has exactly that user’s moderation permissions: it is refused if they cannot moderate the space.
string
required
string
required
"removed"
required
string
string
The moderator the key acts for. The request then has exactly that moderator’s permissions. Omit it to act as the project.
Returns — Promise<{ message: string; moderationStatus: string }>

spaces.handleSpaceChatReport

Resolves a report against a space-conversation message: remove the message, ban the user, and/or dismiss.
string
required
string
required
("remove-message" | "ban-user" | "dismiss")[]
required
dismiss cannot be combined with the other actions.
string
Optional. The message is read from the report; if sent, it must be the reported message.
string
Optional. The server bans the author of the reported message; if sent, this must be that author.
string
string
Stored as the report’s resolution note.
string
The moderator the key acts for. The request then has exactly that moderator’s permissions. Omit it to act as the project.
Returns — Promise<{ message: string; code: string }>