Skip to main content

Send a message

POST 

/chat.post

Send a message to a chat. Messages can be plain markdown text, rich Block Kit layouts, or polls.

Destination (ONE of the following is required):

  • chatId - Post to an existing chat by its ID
  • groupId - Post to a group chat
  • userIds - Post to a DM or Multi-DM with the specified users

You must specify exactly one destination. Specifying multiple destinations (e.g., both chatId and groupId) will return a 400 error.

Mentions use Slack's token syntax with Slack's semantics: <@ID> mentions a principal (a user or bot, e.g. <@7861a4c6-765a-495d-898d-fae3d8fbba2d> — resolvable via user.info), <!subteam^ID> mentions a group or channel, notifying its members (resolvable via group.info), and <!channel> notifies everyone in the chat. When rendered in the client, the tag will automatically be replaced with the human-readable display name (or "everyone" for <!channel>). On write, either token form is accepted for any mentionable ID; the legacy <@all> broadcast alias is accepted; and a Slack-style |label suffix (e.g. <@7861a4c6-…|Rob>, <!subteam^59c1a4d2-…|@eng>) is accepted and ignored — the mentioned entity's live display name is always used. Write-side acceptance is identical on every API version. Messages read back always carry bare canonical tokens, and <!channel> for the broadcast — on API versions from 2026-08-07; clients pinned to older versions read the older grammar (<@ID> for every mention, <@all>). Slack forms Roam does not implement are reserved and stay literal text: <#ID> channel links, <!here>, and <!everyone>.

Custom sender (optional): see the Sender Profiles guide.

  • sender.name / sender.imageUrl are per-message display overrides, stored on the message itself.
  • sender.id authors the message as a configured bot persona (Roam Administration > Developer > edit your app > Add Bot Persona). Ids that don't match a configured persona are accepted and ignored — the message is authored by the app's root identity. Sending never creates or renames personas.
  • Personal access tokens: Reject the sender field with 400. PATs always post as their personal bot.

Access: Organization tokens can post to chats the bot is a member of, and to public groups in the workspace without joining. Personal tokens can post only where the owner is a member (403 not_in_chat for an unjoined public group).

Required scope: chat:send_message or chat:write


OpenAPI Spec: chat-v1.json

Request

Responses

Message posted or scheduled successfully. Immediate posts return chatId (and timestamp when sync is set). Scheduled posts (sendAt) return chatId, scheduledMessageId, and sendAt. All success bodies include "ok": true — see Responses and Errors.