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). Full membership matrix: Chat.

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.