The Events API is a streamlined way to build apps and bots that respond to activities in Slack. When you use the Events API directly over HTTP, Slack calls you.
You designate a public HTTP endpoint that your app listens on, choose what events to subscribe to, and voilà: Slack sends the appropriate events to you.
All you need is a Slack app and a secure place for us to send your events. With the Events API, you can do the following:
You can also use the Events API via Socket Mode to receive events through a dynamic private WebSocket, rather than a static public HTTP endpoint. This is useful for those developing behind a corporate firewall, or have other security concerns.
If you want to publish and distribute your app via the Slack Marketplace, however, you'll want to use HTTP.
Many apps built using the Events API will follow the same abstract event-driven sequence:
If your app is a bot listening to messages with specific trigger phrases, that event loop may play out something like the following:
message.channels
event, as per its bot subscription and membership in #random.chat.postMessage
from the Web API to post that message to #random.Using the Web API with the Events API empowers your app or bot to do much more than just listen and reply to messages.
Let's get started!
The Events API is recommended over the RTM API for most use cases. If you're already familiar with HTTP and are comfortable maintaining your own server, handling the request and response cycle of the Events API should be familiar. If the world of web APIs is new to you, the Events API is a great next step after mastering incoming webhooks or the Web API.
Before starting, you may want to make a few early decisions about your application architecture and approach to consuming events. The Events API is best used in conjunction with other platform features.
One way to use the Events API is as an alternative to opening WebSocket connections to the RTM API. Why choose the Events API over the RTM API? Instead of maintaining one or more long-lived connections for each workspace an application is connected to, you can set up one or more endpoints on your own servers to receive events atomically in near real-time. For more information, refer to Events API FAQ.
Some developers may want to use the Events API as a kind of redundancy for their existing WebSocket connections. Other developers will use the Events API to receive information around the workspaces and users they are acting on behalf, to improve their slash commands, bot users, notifications, or other capabilities. With app events, you can track app uninstallation, token revocation, Enterprise Grid migration, and more. Handle anything else your app does by using incoming webhooks and other write-based web API methods.
The Events API leverages Slack's existing object-driven OAuth scope system to control access to events. For example, if your app has access to files through the files:read
scope, you can choose to subscribe to any or none of the file-related events such as file_created
and file_deleted
.
You will only receive events that users who have authorized your app can "see" on their workspace (that is, if a user authorizes access to private channel history, you'll only see the activity in private channels they are a member of, not all private channels across the workspace).
Bot users may also subscribe to events on their own behalf. The bot
scope requested when workspaces install your bot covers events access for both the Events API and the Real Time Messaging API.
To begin working with the Events API, you'll need to create a Slack app if you haven't already. While managing your application, find the Event Subscriptions setting and use the toggle to turn it on.
After a little more configuration, you'll be able to select all the event types you want to subscribe to.
Request URLs operate similarly to slash command invocation URLs, and message button action URLs:
Since your application will have only one Events API Request URL, you'll need to do any additional dispatch or routing server-side after receiving event data.
Your Request URL will receive JSON-based payloads containing wrapped event types. The volume of events will vary depending on the events you subscribe to, and the size and activity of the workspaces that install your application.
Your Request URL might receive many events and requests. Consider decoupling your ingestion of events from the processing and reaction to them. Review the section on rate limiting to better understand the maximum event volume you may receive.
Your Event Request URL must be confirmed before saving this form. If your server takes some time to "wake up" and your initial attempt at URL verification fails due to a timeout, use the retry button to attempt verification again. Careful, response URLs are case-sensitive.
If you don't wish to expose a public, static HTTP endpoint to communicate with Slack, Socket Mode can help.
The events sent to your Request URL may contain sensitive information associated with the workspaces having approved your Slack app. To ensure that events are being delivered to a server under your direct control, we must verify your ownership by issuing you a challenge request.
After you've completed typing your URL, we'll dispatch a HTTP POST to your request URL. We'll verify your SSL certificate and we'll send a application/json
POST body containing three fields:
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
This event does not require a specific OAuth scope or subscription. You'll automatically receive it whenever configuring an Events API request URL. The attributes Slack sends include:
token
: This deprecated verification token is proof that the request is coming from Slack on behalf of your application. You'll find this value in the App Credentials section of your app's application management interface. Verifying this value is more important when working with real events after this verification sequence has been completed. When responding to real events, always use the more secure signing secret process to verify Slack requests' authenticity.challenge
: a randomly generated string produced by Slack. The point of this string is that you'll respond to this request with a response body containing this value.type
: this payload is similarly formatted to other event types you'll encounter in the Events API. To help you differentiate URL verification requests form other event types, we inform you that this is of the url_verification
variety.Once you receive the event, complete the sequence by responding with HTTP 200 and the challenge
attribute value.
Responses can be sent in plaintext:
HTTP 200 OK
Content-type: text/plain
3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
Alternatively, if you're feeling more formal, respond with application/x-www-form-urlencoded
and a named challenge
parameter:
HTTP 200 OK
Content-type: application/x-www-form-urlencoded
challenge=3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
Or if you feel like showing off, respond with application/json
:
HTTP 200 OK
Content-type: application/json
{"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}
Once URL verification is complete, you'll see a green check mark celebrating your victory.
If you receive an error from your server, a timeout, or other exceptional condition occurs, you'll see error messages that will hopefully help you understand what's amiss before you try again.
Especially when working with large workspaces, many workspaces, or subscribing to a large number of events, de-coupling the processing of and reaction to events is key. With this challenging handshake complete, you're ready to open up our event type catalog and decide which events to subscribe to.
After configuring and validating your Request URL, it's time to subscribe to the event types you find fascinating, useful, or necessary.
The subscription manager is split into two sections:
bot
required. As with workspace events, you'll only receive events perspectival to your bot user.Some event types are not available in bot user subscriptions. Consult a specific event's documentation page for information on whether that event is supported for bot users.
The Events API is backed by the same OAuth permission scoping system powering your Slack App.
If workspaces have already installed your application, your Request URL will soon begin receiving your configured event subscriptions.
For any workspaces that have yet to install your application, you'll need to request the specific OAuth scopes corresponding to the event types you're subscribing to. If you're working on behalf of a bot user, you'll need your bot installed the typical way, using the bot
OAuth scope.
Authorize users for your Event Consumer app through the standard OAuth flow. Be sure to include all of the necessary scopes for the events your app wants to receive. Consult our index of the available event types with corresponding OAuth scopes.
With all this due preparation out of the way, it's time to receive and handle all those event subscriptions.
Your Request URL will receive a request for each event matching your subscriptions. One request, one event.
You may want to consider the number of workspaces you serve, the number of users on those workspaces, their volume of messages, and other activity to evaluate how many requests your Request URL may receive and scale accordingly.
When an event in your subscription occurs in an authorized user's account, we'll send an HTTP POST request to your Request URL. The event will be in the Content-Type: application/json
format:
{
"type": "event_callback",
"token": "XXYYZZ",
"team_id": "T123ABC456",
"api_app_id": "A123ABC456",
"event": {
"type": "name_of_event",
"event_ts": "1234567890.123456",
"user": "U123ABC456",
...
},
"event_context": "EC123ABC456",
"event_id": "Ev123ABC456",
"event_time": 1234567890,
"authorizations": [
{
"enterprise_id": "E123ABC456",
"team_id": "T123ABC456",
"user_id": "U123ABC456",
"is_bot": false,
"is_enterprise_install": false,
}
],
"is_ext_shared_channel": false,
"context_team_id": "T123ABC456",
"context_enterprise_id": null
}
The token
and api_app_id
fields help you identify the validity and intended destination of the request, respectively.
The authorized_users
property is an array that contains a set of one or more users
who are authorized to view the event. A user can be a bot user or a human user who
installed the app. For each user in the authorized_users
property:
The team_id
property on the event's outer payload will mirror the first element in the authorized_users
array. If you need a complete list of every authorized user for an event, you can use
apps.event.authorizations.list.
The event
attribute contains a JSON hash for the corresponding event type. The event wrapper is an event envelope of sorts, and the event field represents the contents of that envelope. Learn more about the event wrapper, including its JSON schema.
Also referred to as the "outer event", or the JSON object containing the event that happened itself:
Field | Type | Description |
---|---|---|
token |
String | The shared-private callback token that authenticates this callback to the application as having come from Slack. Match this against what you were given when the subscription was created. If it does not match, do not process the event and discard it. Example: JhjZd2rVax7ZwH7jRYyWjbDl |
team_id |
String | The unique identifier for the workspace/team where this event occurred. Example: T461EG9ZZ |
api_app_id |
String | The unique identifier for the application this event is intended for. Your application's ID can be found in the URL of the your application console. If your Request URL manages multiple applications, use this field along with the token field to validate and route incoming requests. Example: A4ZFV49KK |
event |
Event type | Contains the inner set of fields representing the event that's happening. Examples below. |
type |
String | This reflects the type of callback you're receiving. Typically, that is event_callback . You may encounter url_verification during the configuration process. The event field's "inner event" will also contain a type field indicating which event type lurks within (below). |
authorizations |
Object | An installation of your app. Installations are defined by a combination of the installing Enterprise Grid org, workspace, and user (represented by enterprise_id , team_id , and user_id inside this field)—note that installations may only have one or two, not all three, defined. authorizations describes one of the installations that this event is visible to. You'll receive a single event for a piece of data intended for multiple users in a workspace, rather than a message per user. Use apps.event.authorizations.list to retrieve additional authorizations. |
event_context |
String | An identifier for this specific event. This field can be used with the apps.event.authorizations.list method to obtain a full list of installations of your app for which this event is visible. |
event_id |
String | A unique identifier for this specific event, globally unique across all workspaces. |
event_time |
Integer | The epoch timestamp in seconds indicating when this event was dispatched. |
The structure of event types vary from type to type, depending on the kind of action or object type they represent. The Events API allows you to tolerate minor changes in event type and object type structures, and to expect additional fields you haven't encountered before or fields that are only conditionally present.
If you're already familiar with the RTM API, you'll find that the inner event
structure is identical to corresponding events, but are wrapped in a kind of event envelope in the callbacks we send to your event Request URL:
Field | Type | Description |
---|---|---|
type |
String | The specific name of the event described by its adjacent fields. This field is included with every inner event type. Examples: reaction_added , message.channels , team_join |
event_ts |
String | The timestamp of the event. The combination of event_ts ,team_id , user_id , or channel_id is intended to be unique. This field is included with every inner event type. Example: 1469470591.759709 |
user |
String | The user ID belonging to the user that incited this action. Not included in all events as not all events are controlled by users. See the top-level callback object's authed_users if you need to calculate event visibility by user. Example: U061F7AUR |
ts |
String | The timestamp of what the event describes, which may occur slightly prior to the event being dispatched as described by event_ts . The combination of ts , team_id , user_id , or channel_id is intended to be unique. Example: 1469470591.759709 |
item |
String | Data specific to the underlying object type being described. Often you'll encounter abbreviated versions of full objects. For instance, when file objects are referenced, only the file's ID is presented. See each individual event type for more detail. |
If multiple users on one workspace have installed your app and can "see" the same event, we will send one event and include a list of users to whom this event is "visible" in the authed_users
field. For example, if a file was uploaded to a channel that two of your authorized users were party to, we would stream the file_uploaded
event once and indicate both of those users in the authed_users
array.
Here's a full example of a dispatched event for reaction_added:
{
"token": "z26uFbvR1xHJEdHE1OQiO6t8",
"team_id": "T123ABC456",
"api_app_id": "A123ABC456",
"event": {
"type": "reaction_added",
"user": "U123ABC456",
"item": {
"type": "message",
"channel": "C123ABC456",
"ts": "1464196127.000002"
},
"reaction": "slightly_smiling_face",
"item_user": "U222222222",
"event_ts": "1465244570.336841"
},
"type": "event_callback",
"authed_users": [
"U123ABC456"
],
"authorizations": [
{
"enterprise_id": "E123ABC456",
"team_id": "T123ABC456",
"user_id": "U123ABC456",
"is_bot": false
}
],
"event_id": "Ev123ABC456",
"event_context": "EC123ABC456",
"event_time": 1234567890
}
Previously, the Events API included a full list of authed_users
, and sometimes authed_teams
, with every event. These fields displayed who the event is visible to. For example, if your app has been installed by two users in a workspace, and the app listens for the file_shared
event, your app might receive an event with authed_users
containing those two users.
Now, authed_users
and authed_teams
are deprecated. Events will contain a single, compact authorizations
field that shows one installation of your app that the event is visible to. In other words, lists of authorizations will be truncated to one element.
Expect a new outer payload on events that looks similar to this one:
{
"token": "z26uFbvR1xHJEdHE1OQiO6t8",
"team_id": "T123ABC456",
"api_app_id": "A123ABC456",
"event": {
"type": "reaction_added",
"user": "U123ABC456",
"item": {
"type": "message",
"channel": "C123ABC456",
"ts": "1464196127.000002"
},
"reaction": "slightly_smiling_face",
"item_user": "U123ABC456",
"event_ts": "1465244570.336841"
},
"type": "event_callback",
"authed_users": [
"U222222222"
],
"authed_teams": [
"T123ABC456"
],
"authorizations": [
{
"enterprise_id": "E123ABC456",
"team_id": "T123ABC456",
"user_id": "U123ABC456",
"is_bot": false
}
],
"event_context": "EC123ABC456",
"event_id": "Ev123ABC456",
"event_time": 1234567890
}
If there's more than one installing party that your app is keeping track of, it's best not to rely on the single party listed in authorizations
to be any particular one.
To get a full list of who can see events, call the apps.event.authorizations.list
method after obtaining an app-level token. Read more on the changes here; they have taken effect for existing apps as of February 24, 2021.
Not all events provide an event_context
. Read more about the events where event_context
is not applicable, and view a full list of those events. Newly created apps are automatically opted into the new form of events: a single, truncated authorizations
field with one authorization shown.
You can also use the apps.event.authorizations.list
method immediately, without yet opting in to the event payload changes. These changes allow Slack to increase the performance of the Events API, delivering events faster.
Your app should respond to the event request with an HTTP 2xx within three seconds. If it does not, we'll consider the event delivery attempt failed. After a failure, we'll retry three times, backing off exponentially. Some best practices are to:
What you do with events depends on what your application or service does.
Maybe it'll trigger you to send a message using chat.postMessage
. Maybe you'll update a leaderboard. Maybe you'll update a piece of data you're storing. Maybe you'll change the world or just decide to do nothing at all.
We don't want to flood your servers with events it can't handle.
Event deliveries currently max out at 30,000 per workspace per app per 60 minutes. If your app would receive more than one workspace's 30,000 events in a 60 minute window, you'll receive app_rate_limited
events describing the conditions every minute.
When rate limited, your Request URL will receive a special app event, app_rate_limited
.
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"type": "app_rate_limited",
"team_id": "T123ABC456",
"minute_rate_limited": 1518467820,
"api_app_id": "A123ABC456"
}
Field guide
token
: the same shared token used to verify other events in the Events APItype
: this specific event type, app_rate_limited
minute_rate_limited
: a rounded epoch time value indicating the minute your application became rate limited for this workspace. 1518467820
is at 2018-02-12 20:37:00 UTC.team_id
: subscriptions between your app and the workspace with this ID are being rate limitedapi_app_id
: your application's ID, especially useful if you have multiple applications working with the Events APIYou'll receive these callbacks for each of the minutes you are rate limited for that workspace.
As Slack sends your request URL events, we ask that you return a HTTP 200 OK for each event you successfully receive. You may respond with a HTTP 301 or 302 and we'll follow up to two redirects in our quest for you to provide us a HTTP 200 success code. Respond with success conditions to at least 5% of the events delivered to your app or risk being temporarily disabled.
Once you've repaired your ability to handle events, re-enable subscriptions by visiting Slack app management, selecting your app, and following the prompts. You'll need to go to Live App Settings if your app is part of the Slack Marketplace.
We consider any of these scenarios a single failure condition:
While we limit the number of failure conditions we'll tolerate over time, we also gracefully retry sending your events according to an exponential backoff strategy.
Maintain a successful response rate of 5% or above to avoid automatic event delivery disabling. Apps receiving less than 1,000 events per hour will not be automatically disabled.
We'll knock knock knock on your server's door, retrying a failed request up to 3 times in a gradually increasing timetable:
With each retry attempt, you'll also be given a x-slack-retry-num
HTTP header indicating the attempt number: 1
, 2
, or 3
. Retries count against the failure limits mentioned below.
We'll tell you why we're retrying the request in the x-slack-retry-reason
HTTP header. These possible values describe their inciting events:
http_timeout
: Your server took longer than 3 seconds to respond to the previous event delivery attempt.too_many_redirects
: We'll follow you down the rabbit hole of HTTP redirects only so far. If we encounter more than 2, we'll retry the request in hopes it won't be that many this time.connection_failed
: We just couldn't seem to connect to your server. Maybe we couldn't find it in DNS or maybe your host is unreachable.ssl_error
: We couldn't verify the veracity of your SSL certificate. Find tips on producing valid SSL certificates here.http_error
: We encountered an HTTP status code that was not in the HTTP 200 OK range. Maybe the request was forbidden. Or you rate limited us. Or the document just could not be found. So we're trying again in case that's all rectified now.unknown_error
: We didn't anticipate this condition arising, but prepared for it nonetheless. For some reason it didn't work; we don't know why yet.If your server is having trouble handling our requests or you'd rather we not retry failed deliveries, provide a HTTP header in your responses indicating that you'd prefer no further attempts. Provide us this HTTP header and value as part of your non-200 OK response:
x-slack-no-retry: 1
By presenting this header, we'll understand it to mean you'd rather this specific event not be re-delivered. Other event deliveries will remain unaffected.
If you're responding with errors, we won't keep sending events to your servers forever.
When your application enters any combination of these failure conditions for more than 95% of delivery attempts within 60 minutes, your application's event subscriptions will be temporarily disabled.
We'll also send you, the Slack app's creator and owner, an email alerting you to the situation. You'll have the opportunity to re-enable deliveries when you're ready.
Manually re-enable event subscriptions by visiting your application's settings. If your app is part of the Slack Marketplace, use your Live App Settings instead of your development app.
Inevitably, the status of your subscriptions will change. New workspaces will sign up for your application. Installing users may leave a workspace. Maybe you make some tweaks to your subscriptions or incite users to request a different set of OAuth scopes.
Beyond your app being disabled, there are a few different types of changes that will affect which events your app is receiving.
When a user installs your app, you'll immediately begin receiving events for them based on your subscription.
Your application's granted OAuth scopes dictate which events in your subscription you receive.
If you've configured your subscription to receive reaction_added
, reaction_removed
, and file_created
events, you won't receive all three unless you request the reactions:read
and files:read
scopes from the user. For example, If you'd only requested files:read
, you'll only receive file_created
events and not reaction_added
or reaction_removed
.
If a user uninstalls your app (or the tokens issued to your app are revoked), events for that user will immediately stop being sent to your app.
If you modify your subscription through the application management interface, the modifications will immediately take effect.
Depending on the modification, the event types, and OAuth scopes you've been requesting from users, a few different things can happen:
files:read
from users and decide to add the file_created
event. Because you already have access to this resource (files), you'll begin receiving file_created
events as soon as you update your subscription.channels:read
from users and decide to add the file_created
event. Because you don't have access to this resource (files), you won't receive file_created
events immediately. You must send your existing users through the OAuth flow again, requesting the files:read
scope. You'll begin to receive file_created
events for each user after they authorize files:read
for your app.Bot users using the Events API exclusively must toggle their presence status. To toggle your bot user's presence when connected exclusively to the Events API, visit your app management console's Bot Users tab.
Learn more about the nuances of bot user presence.
Browse all available events here.
Want to browse the list of events and even some of their properties programmatically? Check out our AsyncAPI spec for the Events API.
Your application has a life of its own. You build it, cultivate it, maintain it, and improve it. But still, stuff happens to your app in the wild. Tokens get revoked, workspaces accidentally uninstall it, and sometimes teams grow up and become part of a massive Enterprise Grid.
Building an integration for Enterprise Grid workspaces? Consult the Enterprise Grid docs for notes on Events API usage and shared channels.
Sophisticated apps want to know what's happening, to situationally respond, tidy up data messes, pause and resume activity, or to help you contemplate the many-folded nuances of building invaluable social software. Your app is interesting, wouldn't you like to subscribe to its newsletter?
Subscriptions to app events require no special OAuth scopes; just subscribe to the events you're interested in and you'll receive them as appropriate for each workspace your app is installed on.