The Real Time Messaging API is a WebSocket-based API that allows you to receive events from Slack in real time and send messages as users. It's sometimes referred to as simply the "RTM API".
It is the basis for all Slack clients. It's also commonly used with the bot user integration to create helper bots for your workspace.
If you prefer events to be pushed to you instead, we recommend using the HTTP-based Events API instead. Most event types supported by the RTM API are also available in the Events API.
New Slack apps may not use any Real Time Messaging API method. Create a classic app and use the V1 Oauth flow to use RTM.
For most applications, Socket Mode is a better way to communicate with Slack.
To begin a RTM session make an authenticated call to the rtm.connect API method. This provides an initial set of workspace metadata and a message server WebSocket URL. Once you have connected to the message server it will provide a stream of events, including both messages and updates to the current state of the workspace. This allows a client to easily maintain a synchronized local copy of all workspace data and messages.
The Websocket URLs provided by rtm.connect
are single-use and are only valid
for 30 seconds, so make sure to connect quickly. If you connect successfully
the first event received will be a hello:
{
"type": "hello"
}
This will be followed by any events that occurred between the call to
rtm.connect
and the connection to the message server. If you're reconnecting
after a network problem this initial set of events may include a response
to the last message sent on a previous connection (with a reply_to
) so a
client can confirm that message was received.
If there was a problem connecting an error will be returned, including a descriptive error message:
{
"type": "error",
"error": {
"code": 1,
"msg": "Socket URL has expired"
}
}
Almost everything that happens in Slack will result in an event being sent to all connected clients. The simplest event is a message sent from a user:
{
"type": "message",
"ts": "1358878749.000002",
"user": "U023BECGF",
"text": "Hello"
}
Every event has a type
property which describes the type of event. Our
servers currently send the following event types:
Event | Description | Works with | |
---|---|---|---|
accounts_changed | The list of accounts a user is signed into has changed | RTM | |
app_home_opened | User clicked into your App Home | Events API | |
app_mention | Subscribe to only the message events that mention your app or bot | Events API | |
app_rate_limited | Indicates your app's event subscriptions are being rate limited | Events API | |
app_requested | User requested an app | Events API | |
app_uninstalled | Your Slack app was uninstalled. | Events API | |
bot_added | A bot user was added | RTM | |
bot_changed | A bot user was changed | RTM | |
call_rejected | A Call was rejected | Events API | |
channel_archive | A channel was archived | RTM | Events API |
channel_created | A channel was created | RTM | Events API |
channel_deleted | A channel was deleted | RTM | Events API |
channel_history_changed | Bulk updates were made to a channel's history | RTM | Events API |
channel_id_changed | A channel ID changed | Events API | |
channel_joined | You joined a channel | RTM | |
channel_left | You left a channel | RTM | Events API |
channel_marked | Your channel read marker was updated | RTM | |
channel_rename | A channel was renamed | RTM | Events API |
channel_shared | A channel has been shared with an external workspace | Events API | |
channel_unarchive | A channel was unarchived | RTM | Events API |
channel_unshared | A channel has been unshared with an external workspace | Events API | |
commands_changed | A slash command has been added or changed | RTM | |
dnd_updated | Do not Disturb settings changed for the current user | RTM | Events API |
dnd_updated_user | Do not Disturb settings changed for a member | RTM | Events API |
email_domain_changed | The workspace email domain has changed | RTM | Events API |
emoji_changed | A custom emoji has been added or changed | RTM | Events API |
external_org_migration_finished | An enterprise grid migration has finished on an external workspace. | RTM | |
external_org_migration_started | An enterprise grid migration has started on an external workspace. | RTM | |
file_change | A file was changed | RTM | Events API |
file_comment_added | A file comment was added | RTM | Events API |
file_comment_deleted | A file comment was deleted | RTM | Events API |
file_comment_edited | A file comment was edited | RTM | Events API |
file_created | A file was created | RTM | Events API |
file_deleted | A file was deleted | RTM | Events API |
file_public | A file was made public | RTM | Events API |
file_shared | A file was shared | RTM | Events API |
file_unshared | A file was unshared | RTM | Events API |
goodbye | The server intends to close the connection soon. | RTM | |
grid_migration_finished | An enterprise grid migration has finished on this workspace. | Events API | |
grid_migration_started | An enterprise grid migration has started on this workspace. | Events API | |
group_archive | A private channel was archived | RTM | Events API |
group_close | You closed a private channel | RTM | Events API |
group_deleted | A private channel was deleted | RTM | Events API |
group_history_changed | Bulk updates were made to a private channel's history | RTM | Events API |
group_joined | You joined a private channel | RTM | |
group_left | You left a private channel | RTM | Events API |
group_marked | A private channel read marker was updated | RTM | |
group_open | You created a group DM | RTM | Events API |
group_rename | A private channel was renamed | RTM | Events API |
group_unarchive | A private channel was unarchived | RTM | Events API |
hello | The client has successfully connected to the server | RTM | |
im_close | You closed a DM | RTM | Events API |
im_created | A DM was created | RTM | Events API |
im_history_changed | Bulk updates were made to a DM's history | RTM | Events API |
im_marked | A direct message read marker was updated | RTM | |
im_open | You opened a DM | RTM | Events API |
invite_requested | User requested an invite | Events API | |
link_shared | A message was posted containing one or more links relevant to your application | Events API | |
manual_presence_change | You manually updated your presence | RTM | |
member_joined_channel | A user joined a public or private channel | RTM | Events API |
member_left_channel | A user left a public or private channel | RTM | Events API |
message | A message was sent to a channel | RTM | Events API |
message.app_home | A user sent a message to your Slack app | Events API | |
message.channels | A message was posted to a channel | Events API | |
message.groups | A message was posted to a private channel | Events API | |
message.im | A message was posted in a direct message channel | Events API | |
message.mpim | A message was posted in a multiparty direct message channel | Events API | |
message_metadata_deleted | Message metadata was deleted | Events API | |
message_metadata_posted | Message metadata was posted | Events API | |
message_metadata_updated | Message metadata was updated | Events API | |
pin_added | A pin was added to a channel | RTM | Events API |
pin_removed | A pin was removed from a channel | RTM | Events API |
pref_change | You have updated your preferences | RTM | |
presence_change | A member's presence changed | RTM | |
presence_query | Determine the current presence status for a list of users | RTM | |
presence_sub | Subscribe to presence events for the specified users | RTM | |
reaction_added | A member has added an emoji reaction to an item | RTM | Events API |
reaction_removed | A member removed an emoji reaction | RTM | Events API |
reconnect_url | Experimental | RTM | |
resources_added | Access to a set of resources was granted for your app | Events API | |
resources_removed | Access to a set of resources was removed for your app | Events API | |
scope_denied | OAuth scopes were denied to your app | Events API | |
scope_granted | OAuth scopes were granted to your app | Events API | |
shared_channel_invite_accepted | A shared channel invite was accepted | Events API | |
shared_channel_invite_approved | A shared channel invite was approved | Events API | |
shared_channel_invite_declined | A shared channel invite was declined | Events API | |
shared_channel_invite_received | A shared channel invite was sent to a Slack user | RTM | Events API |
star_added | A member has starred an item | RTM | Events API |
star_removed | A member removed a star | RTM | Events API |
subteam_created | A User Group has been added to the workspace | RTM | Events API |
subteam_members_changed | The membership of an existing User Group has changed | RTM | Events API |
subteam_self_added | You have been added to a User Group | RTM | Events API |
subteam_self_removed | You have been removed from a User Group | RTM | Events API |
subteam_updated | An existing User Group has been updated or its members changed | RTM | Events API |
team_access_granted | Access to a set of teams was granted to your org app | Events API | |
team_access_revoked | Access to a set of teams was revoked from your org app | Events API | |
team_domain_change | The workspace domain has changed | RTM | Events API |
team_join | A new member has joined | RTM | Events API |
team_migration_started | The workspace is being migrated between servers | RTM | |
team_plan_change | The account billing plan has changed | RTM | |
team_pref_change | A preference has been updated | RTM | |
team_profile_change | The workspace profile fields have been updated | RTM | |
team_profile_delete | The workspace profile fields have been deleted | RTM | |
team_profile_reorder | The workspace profile fields have been reordered | RTM | |
team_rename | The workspace name has changed | RTM | Events API |
tokens_revoked | API tokens for your app were revoked. | Events API | |
url_verification | Verifies ownership of an Events API Request URL | Events API | |
user_change | A member's data has changed | RTM | Events API |
user_huddle_changed | A user's huddle status has changed | RTM | Events API |
user_profile_changed | A user's profile data has changed | RTM | Events API |
user_resource_denied | User resource was denied to your app | Events API | |
user_resource_granted | User resource was granted to your app | Events API | |
user_resource_removed | User resource was removed from your app | Events API | |
user_status_changed | A user's status has changed | RTM | Events API |
user_typing | A channel member is typing a message | RTM | |
workflow_deleted | A workflow that contains a step supported by your app was deleted | Events API | |
workflow_published | A workflow that contains a step supported by your app was published | Events API | |
workflow_step_deleted | A workflow step supported by your app was removed from a workflow | Events API | |
workflow_step_execute | A workflow step supported by your app should execute | Events API | |
workflow_unpublished | A workflow that contains a step supported by your app was unpublished | Events API |
New event types will be added in the future, clients should be able to handle unexpected event types.
You can send a message to Slack by sending JSON over the WebSocket connection.
Every event should have a unique (for that connection) positive integer ID. All replies to that message will include this ID allowing the client to correlate responses with the messages sent; replies may be "out of order" due to the asynchronous nature of the message servers.
Also, as with events sent from the server, each event sent by the client has a
string type
specifying what the message does — chat messages are of type message
.
So to post the text "Hello world" to a channel, you can send this JSON:
{
"id": 1,
"type": "message",
"channel": "C024BE91L",
"text": "Hello world"
}
You can send a message to a private group or direct message channel in the
same way, but using a group ID (C024BE91L
) or direct message channel ID (D024BE91L
).
To send a message both as and to the authenticating user, use the correct direct message channel ID for that user. The direct message ID can be found as part of the response to rtm.connect
, or by consulting conversations.list
.
The RTM API only supports posting simple messages formatted using our
default message formatting mode. It does not support
attachments or other message formatting modes. To post a
more complex message as a user clients can call the
chat.postMessage Web API method with as_user
set to true.
User mentions over RTM should use the User ID-based <@U123ABC>
syntax:
{
"id": 2,
"type": "message",
"channel": "C024BE91L",
"text": "Hello <@U123ABC>"
}
Once the JSON has been sent to the server visual clients should immediately display the text in the channel, grayed out or otherwise marked to indicate that it is "pending". At some point after that, usually a few milliseconds later, the server will send a confirmation that the message was received:
{
"ok": true,
"reply_to": 1,
"ts": "1355517523.000005",
"text": "Hello world"
}
Replies to messages sent by clients will always contain two properties: a
boolean ok
indicating whether they succeeded and an integer reply_to
indicating which message they are in response to.
In the case of a reply to a chat message, if successful, the reply will contain the canonical recorded timestamp of the message. All messages within a single channel are guaranteed to have a unique timestamp which is ASCII sortable. Given the precision of the timestamp, clients should treat these timestamps as strings, not floats/doubles. Once a successful reply has been returned, the message in the chat log should no longer be grayed out - it has now been delivered.
Chat message replies also contain the message text, which may vary from the sent message due to URL detection.
If there is an error processing an event the message server will reply with an error. For example:
{
"ok": false,
"reply_to": 1,
"error": {
"code": 2,
"msg": "message text is missing"
}
}
Clients can send a typing indicator to indicate that the user is currently writing a message to send to a channel:
{
"id": 1,
"type": "typing",
"channel": "C024BE91L"
}
This can be sent on every key press in the chat input unless one has been sent in the last three seconds. Unless there is an error the server will not send a reply, but it will send a "user_typing" event to all workspace members in the channel.
User and bot user presence on the RTM API is complicated enough to warrant an entire document. Learn all about presence subscriptions and batch presence events here.
presence_change
events are not dispatched without presence subscriptions established with presence_sub
. Relatedly, current user presence status is no longer communicated in rtm.start
. Learn more.
Clients should try to quickly detect disconnections, even in idle periods, so that users can easily tell the difference between being disconnected and everyone being quiet. Not all web browsers support the WebSocket ping spec, so the RTM protocol also supports ping/pong messages. When there is no other activity clients should send a ping every few seconds. To send a ping, send the following JSON:
{
"id": 1234, // ID, see "sending messages" above
"type": "ping",
...
}
You can supply any number of extra "flat" arguments (that is: only scalar values, no arrays or objects). These will be included in the pong message that is sent back. For example, a client could include a local timestamp in the ping message so it can calculate round-trip latency:
{
"id": 1234,
"type": "ping",
"time": 1403299273342
}
This will be included in the reply from the server:
{
"reply_to": 1234,
"type": "pong",
"time": 1403299273342
}
The message server will disconnect any client that sends a message longer than 16 kilobytes. This includes all parts of the message, including JSON syntax, not just the message text. Clients should limit messages sent to channels to 4000 characters, which will always be under 16k bytes even with a message comprised solely of non-BMP Unicode characters at 4 bytes each. If the message is longer a client should prompt to split the message into multiple messages, create a snippet or create a post.
As with all Slack APIs, the RTM API is subject to rate limits. Clients should not send more than one message per second sustained. If you do you may receive an error message or be disconnected.
WebSockets are a standard way to open a long-lived bi-directional communication channel with a server over TCP. It's the protocol used when connecting to our RTM API. Many contributions from our community support the particulars of connecting to Slack via a WebSocket.
rtm.connect
vs. rtm.start
There are currently two ways to reserve websocket connections.
rtm.connect
concerns itself only with getting your app connected to the RTM API, and only includes limited information about the connecting user and housing workspace.
rtm.start
includes not only an entire kitchen sink but an entire kitchen filled with information about the user, its workspace, its channels, its current state in the universe. rtm.start
is naturally more difficult to use with Enterprise Grid and other large workspaces.
We strongly recommend using rtm.connect
to reserve your websocket connections and use the Web API in tandem to collect all the state information your app needs.
Both APIs are useful for different reasons, despite them both serving the same kind of data. Find out why to choose one or the other (or both!) in the Events API FAQ.
Since new Slack apps don't connect to rtm.connect
, you'll need to have a classic Slack app to get started. If you haven't created one yet, click here to make one: