The rundown | |||
---|---|---|---|
Read this if: | You're still experimenting, prototyping, and exploring. | ||
Read first: | Starting with Slack apps | SDKs and Tools for building on Slack | Block Kit |
Read next: | Events |
The Events API is a streamlined, easy way to build apps and bots that respond to activities in Slack. All you need is a Slack app and a secure place for us to send your events.
Tell us where to send your carefully selected event types and we'll deliver them with grace, security, and respect. We'll even retry when things don't work out.
Subscribe to the event types you want and don't worry about the events you don't need.
The event types sent to you are directly tied to the OAuth permission scopes awarded as users install your Slack App.
Slack Apps including bot users can subscribe to events related to the channels and direct message conversations they are party to. Build bots without a bothersome bevy of RTM API websockets.
Find the right mix of user-based and bot user-based event subscriptions for your needs. Use both the Events and RTM APIs together for more redundancy and concern separation. Choose the technical implementation that's right for you.
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:
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.
For many, the Events API is drastically simpler to integrate with than the real time messaging API. If you're already familiar with HTTP and comfortable maintaining your own server, handling the request and response cycle of the Events API should be old hat. 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.
One way to use the Events API is as an alternative to opening websocket connections to the real time messaging API. Instead of maintaining one or more long-lived connections for each workspace an application is connected to, you simply set up one or more endpoints on your own servers to receive events atomically in near real-time.
Some developers may want to use the Events API as a kind of redundancy for their existing websocket connections.
And 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.
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 like file_created
and file_deleted
.
You will only receive events that users who've 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" configuration page 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:
They all receive a HTTP POST containing data in response to activity.
In the Events API, your Events API Request URL is the target location where all the events your application is subscribed to will be delivered, regardless of the workspace or event type.
Since your application will have only one Events 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.
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 little game of cat and mouse is that you're going to 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.Careful, response URLs are case sensitive.
Responding to the challenge
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 retry once ready.
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.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, and 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:
{
"token": "XXYYZZ",
"team_id": "TXXXXXXXX",
"api_app_id": "AXXXXXXXXX",
"event": {
"type": "name_of_event",
"event_ts": "1234567890.123456",
"user": "UXXXXXXX1",
...
},
"type": "event_callback",
"authed_users": [
"UXXXXXXX1",
"UXXXXXXX2"
],
"event_id": "Ev08MFMKH6",
"event_time": 1234567890
}
The token
, team
, and api_app_id
fields help you identify the validity, origin, and destination of the request.
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 — much 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: |
team_id |
String | The unique identifier for the workspace/team where this event occurred. Example: |
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: |
event |
Event Type | Contains the inner set of fields representing the event that's happening. |
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` fields "inner event" will also contain a type field indicating which event type lurks within (down below) |
authed_users |
Array | An array of string-based User IDs. Each member of the collection represents a user that has installed your application/bot and indicates the described event would be visible to those users. You'll receive a single event for a piece of data intended for multiple users in a workspace, rather than a message per user. |
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.
If you're already familiar with the real time messaging API, you'll find that the inner event
structure is identical to corresponding events, but they 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: |
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.
"Time is the moving image of eternity" — Plato. Example: |
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: |
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: |
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": "T061EG9RZ",
"api_app_id": "A0FFV41KK",
"event": {
"type": "reaction_added",
"user": "U061F1EUR",
"item": {
"type": "message",
"channel": "C061EG9SL",
"ts": "1464196127.000002"
},
"reaction": "slightly_smiling_face",
"item_user": "U0M4RL1NY"
"event_ts": "1465244570.336841"
},
"type": "event_callback",
"authed_users": [
"U061F7AUR"
],
"event_id": "Ev9UQ52YNA",
"event_time": 1234567890
}
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.
Maintain a response success rate of at least 5% of events per 60 minutes to prevent automatic disabling.
Respond to events with a HTTP 200 OK as soon as you can. Avoid actually processing and reacting to events within the same process. Implement a queue to handle inbound events after they are received.
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 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": "T123456",
"minute_rate_limited": 1518467820,
"api_app_id": "A123456"
}
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 directory.
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 attempttoo_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 unreachablessl_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 and 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.
Just 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 redelivered. 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 directory, 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 events types, and OAuth scopes you've been requesting from users, a few different things can happen:
For example, you've been requesting 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.
For example, you've been requesting 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.
Events will immediately stop being sent for all users who have installed your app. Their OAuth scopes and authorizations will not be affected.
If you weren't granted the permission scopes for the removed event subscription, then nothing really changes. You weren't receiving those events anyway and you won't be receiving them now either.
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.
You may subscribe to these events using the Events API:
Event | Description | Required Scope |
---|---|---|
app_home_opened | User clicked into your App Home | None |
app_mention | Subscribe to only the message events that mention your app or bot | app_mentions:read |
app_rate_limited | Indicates your app's event subscriptions are being rate limited | None |
app_requested | User requested an app | admin.apps:read |
app_uninstalled | Your Slack app was uninstalled. | None |
call_rejected | A call was rejected | calls:read |
channel_archive | A channel was archived | channels:read |
channel_created | A channel was created | channels:read |
channel_deleted | A channel was deleted | channels:read |
channel_history_changed | Bulk updates were made to a channel's history | channels:history |
channel_left | You left a channel | channels:read |
channel_rename | A channel was renamed | channels:read |
channel_shared | A channel has been shared with an external workspace | channels:read |
channel_unarchive | A channel was unarchived | channels:read |
channel_unshared | A channel has been unshared with an external workspace | channels:read |
dnd_updated | Do not Disturb settings changed for the current user | dnd:read |
dnd_updated_user | Do not Disturb settings changed for a member | dnd:read |
email_domain_changed | The workspace email domain has changed | team:read |
emoji_changed | A custom emoji has been added or changed | emoji:read |
file_change | A file was changed | files:read |
file_comment_added | A file comment was added | files:read |
file_comment_deleted | A file comment was deleted | files:read |
file_comment_edited | A file comment was edited | files:read |
file_created | A file was created | files:read |
file_deleted | A file was deleted | files:read |
file_public | A file was made public | files:read |
file_shared | A file was shared | files:read |
file_unshared | A file was unshared | files:read |
grid_migration_finished | An enterprise grid migration has finished on this workspace. | None |
grid_migration_started | An enterprise grid migration has started on this workspace. | None |
group_archive | A private channel was archived | groups:read |
group_close | You closed a private channel | groups:read |
group_deleted | A private channel was deleted | groups:read |
group_history_changed | Bulk updates were made to a private channel's history | groups:history |
group_left | You left a private channel | groups:read |
group_open | You created a group DM | groups:read |
group_rename | A private channel was renamed | groups:read |
group_unarchive | A private channel was unarchived | groups:read |
im_close | You closed a DM | im:read |
im_created | A DM was created | im:read |
im_history_changed | Bulk updates were made to a DM's history | im:history |
im_open | You opened a DM | im:read |
invite_requested | User requested an invite | admin.invites:read |
link_shared | A message was posted containing one or more links relevant to your application | links:read |
member_joined_channel | A user joined a public or private channel | channels:read |
member_left_channel | A user left a public or private channel | channels:read |
message | A message was sent to a channel | channels:history |
message.app_home | A user sent a message to your Slack app | None |
message.channels | A message was posted to a channel | channels:history |
message.groups | A message was posted to a private channel | groups:history |
message.im | A message was posted in a direct message channel | im:history |
message.mpim | A message was posted in a multiparty direct message channel | mpim:history |
pin_added | A pin was added to a channel | pins:read |
pin_removed | A pin was removed from a channel | pins:read |
reaction_added | A member has added an emoji reaction to an item | reactions:read |
reaction_removed | A member removed an emoji reaction | reactions:read |
resources_added | Access to a set of resources was granted for your app | None |
resources_removed | Access to a set of resources was removed for your app | None |
scope_denied | OAuth scopes were denied to your app | None |
scope_granted | OAuth scopes were granted to your app | None |
star_added | A member has starred an item | stars:read |
star_removed | A member removed a star | stars:read |
subteam_created | A User Group has been added to the workspace | usergroups:read |
subteam_members_changed | The membership of an existing User Group has changed | usergroups:read |
subteam_self_added | You have been added to a User Group | usergroups:read |
subteam_self_removed | You have been removed from a User Group | usergroups:read |
subteam_updated | An existing User Group has been updated or its members changed | usergroups:read |
team_domain_change | The workspace domain has changed | team:read |
team_join | A new member has joined | users:read |
team_rename | The workspace name has changed | team:read |
tokens_revoked | API tokens for your app were revoked. | None |
url_verification | Verifies ownership of an Events API Request URL | None |
user_change | A member's data has changed | users:read |
user_resource_denied | User resource was denied to your app | None |
user_resource_granted | User resource was granted to your app | None |
user_resource_removed | User resource was removed from your app | None |
If you want to bookmark that handy list, do so 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 built it, you cultivate it, you maintain 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.
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 below and you'll receive them as appropriate for each workspace your app is installed on.
Event | Description | Required Scope |
---|---|---|
app_mention | Subscribe to only the message events that mention your app or bot | app_mentions:read |
app_rate_limited | Indicates your app's event subscriptions are being rate limited | None |
app_uninstalled | Your Slack app was uninstalled. | None |
grid_migration_finished | An enterprise grid migration has finished on this workspace. | None |
grid_migration_started | An enterprise grid migration has started on this workspace. | None |
tokens_revoked | API tokens for your app were revoked. | None |
url_verification | Verifies ownership of an Events API Request URL | None |
Operational detail for each event is available in its respective documentation.
chat.postMessage
. Handle anything else your app does by using incoming webhooks and other write-based web API methods.message.channels
happen frequently on typical workspaces. im_history_changed
on the other hand is a rare occurrence on even the busiest of workspaces.