Direct Messages
DMs are workspace-scoped multi-party conversations. They reuse the messages table — every DM message sets direct_conversation_id and leaves channel_id null.
#Endpoints
GET /api/dms?workspace_id= # caller's conversations in a workspace
POST /api/dms # { workspace_id, member_ids }
GET /api/dms/{conversation_id}/messages?after_seq=&limit=
POST /api/dms/{conversation_id}/messages # { body, quoted_message_id?, nonce? }
POST /api/dms/{conversation_id}/read # { seq }
Conversations include their members hydrated from users. The member_ids list on create is deduplicated and the caller is added automatically.
The web sidebar lists existing DMs and also derives a People section from DM members and hydrated message authors. Users appear there automatically as conversation context is loaded; clicking a person opens their DM when one exists, otherwise it opens the profile pane with a Message action.
POST to /dms/{id}/messages increments a per-conversation sequence on messages.channel_seq and emits a durable private event into the workspace event stream so DM lists and unread counts stay live for conversation members. nonce has the same retry-safe idempotency behavior as channel message creation.
POST /dms/{id}/read updates the caller's monotonic read pointer for that conversation and emits a private dm.read event only to the caller's own sessions.
#Membership
- Listing conversations requires workspace membership.
- Sending a DM requires membership in the conversation
- DM creation requires that all
member_idsare members of the same - Editing, deleting, reacting to, attaching uploads to, or opening threads on
(direct_conversation_members).
workspace.
a DM message requires direct conversation membership. Edits and deletes are author-only.
#Threads
DM root messages support the same one-level thread model as channel messages. Thread replies carry direct_conversation_id, use thread_seq, and do not appear in the root DM timeline or unread root-message sequence.
#What is intentionally missing
- DM-only auth tokens.
- One-on-one vs group distinctions in the API surface — the client decides
- DM-only search. Workspace/channel search excludes DMs; DM search needs a
based on member count.
separate endpoint so private messages never leak into channel results.