Features

Direct Messages

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}                          # direct access, including closed DMs
DELETE /api/dms/{conversation_id}                        # close for the current human user
POST /api/dms/{conversation_id}/open                     # reopen for the current human user
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 and a can_send flag. The flag is false when every other member has been deleted or removed from the workspace. Root messages and thread replies return 409 Conflict while the conversation has no active recipient. 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 with exactly that person and the current user, otherwise it opens the profile pane with a Message action. Groups containing the person do not match. Explicit Message and Start DM actions use the server to create or reopen that exact one-to-one conversation. Failed starts show an error and retain the selected recipient ID for retry. The Start DM form searches the full workspace member directory, including people who have not posted or joined a DM. Opening it refreshes the directory so newly joined members can be found without reloading. It resolves an unambiguous name or handle match, asks you to select a result when multiple people match, and also accepts an explicit usr_... user ID. Closing the dialog or changing the current view prevents a late response from taking over navigation. Self-DMs remain unsupported and show the server's validation error.

Closing a DM only hides it from the current user's sidebar. Membership, history, routes, and read state remain intact for every member. Direct links still resolve. Reopening the same one-to-one member set, using the explicit open endpoint, or receiving a new root message makes the conversation visible again. The web sidebar exposes Close and an eight-second Undo action. Bot tokens cannot close or reopen a human user's sidebar state.

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
  • (direct_conversation_members).

  • DM creation requires that all member_ids are members of the same
  • workspace.

  • Editing, deleting, reacting to, attaching uploads to, or opening threads on
  • 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.

Search supports one direct conversation through direct_conversation_id. The caller must be a conversation member; workspace and channel searches continue to exclude direct messages.

#What is intentionally missing

  • DM-only auth tokens.
  • One-on-one vs group distinctions in the API surface — the client decides
  • based on member count.