Legacy bots

Slack apps act independently of a user token. Build a bot user powered by only the specific permissions it needs. Check out Slack apps now.

What are bots?

A bot is a type of app designed to interact with users via conversation. You can enable conversations between users and apps in Slack by building these bots.

A conversation between @celeste and @officebot

A bot is the same as a regular app: it can access the same range of APIs and do all of the magical things that a Slack App can do. But when you build a bot for your app, you're giving that app a face, a name, and a personality, and encouraging users to talk to it.

Your bot can send DMs, be mentioned by users, post messages or upload files, and be invited to channels - or kicked out.

Creating a bot user

Since your bot is capable of doing everything that an app can do, we're going to limit our focus to a common use case for bots. The following steps will get you to the point where you have a bot waiting for messages and sending responses. From there, you can begin adding any kind of app logic you can imagine.

Before you start, you'll need an app. If you don't already have one, click the following button to create it:

Create your app

To use your app as a bot, first you'll need to create a bot user for it.

Head to your app's settings page and click the Bot Users feature in the navigation menu. You'll be presented with a button marked Add a Bot User, and when you click on it, you'll see a screen where you can configure your app's bot user with the following information:

  • Display name: the name displayed to other users when the bot posts messages, the bot's profile is viewed, etc.
  • Default username: the string used when the bot is mentioned in a message. This username may be modified slightly from the default when it is installed to a workspace where that username is already reserved. This modification is an incrementing number appended to the username β€” so @username might become @username2.
  • Always Show My Bot as Online: we recommend you enable this feature so that your bot always appears to be ready to receive input (which it probably will be). When disabled, you'll have to programmatically set its online presence.

Once you've completed these fields, click Add Bot User and then Save Changes.

Great, you've just created a bouncing baby bot! Don't leave the app settings yet though, there's still a bit of configuration left to do.

Configuring the Events API

The Events API is a bot's eyes and ears. It gives the bot a way to react to posted messages, changes to channels, and other activities that happen in Slack. When these events happen, a data payload will be sent to your bot, and it can use that data to form a useful response.

Give your bot access to the Events API as follows:

  1. From your app's settings, click the Event Subscriptions feature in the navigation menu.
  2. Switch the Enable Events toggle to on and you'll be presented with a new screen of options.
  3. You'll need to configure the Request URL that the data payloads will be pushed to. This URL needs to be verified first, as outlined in the Events API docs.
  4. Then you'll add some individual event subscriptions. For our bot, we're interested in the Bot Events, so click on the Add Bot User Event button.
  5. There are lots of different event types you could add, but for the purposes of our tutorial let's add two event subscriptions - app_mention which sends events when someone mentions your bot, and message.channels which sends events when a new message is posted in a public channel.
  6. Click Save Changes.

Good news! Your bot is looking more and more life-like, and now it's ready to find a home.

Installing the bot to a workspace

A bot user is added to a workspace by installing the app the bot is associated with. Once done, you'll get a bot token that is imbued with the bot scope. This token can be used with a subset of Web API methods that we'll discuss later.

If you had already installed your app in the past, you'll need to reinstall to grant the additional bot scope. The process is the same either way:

  1. On your app's settings page, click the Install App settings item in the navigation menu.
  2. Click Install App to your Workspace. If you had already installed your app, the button to click will instead be called Reinstall App.
  3. On the permissions authorization page, click Authorize.

Your app is now installed to that workspace, but you still need to invite it into individual channels. You should also invite the bot to a public channel somewhere in your workspace.

Once installed, you'll have generated a bot token that you should store for use later on β€” you can find it in your app's settings under Install App > Bot User OAuth Access Token.

Bot tokens can also be generated using the OAuth install flow if you are distributing your app beyond your own workspace.

Your bot should now be happily residing in the channel picked during the install process. It will be listening for users posting in that channel, and for posted messages that mention it. Now you need to tell it what to do when it hears something.

Handling events

Previously, we configured the event subscriptions for your app β€” but now we have to actually do something with the data that will be sent with each event.

Let's imagine a conversational bot that responds to being mentioned by sending a couple of follow-up messages:

Example conversation between a user and a bot with the user asking the bot to tell a joke

There are four events triggered in this conversation: the first is an app_mention event from the first message that mentions the bot; the next three are message events for each of the messages posted by Johnny. Our bot will need to be able to interpret each event and respond accordingly.

We've avoided showing you any specific code up until now, but in the following steps we're going to explain the process and then show simplified Express/Node.js examples of what your app logic should look like. These examples translate readily into most modern programming languages.

Receiving events

The first thing we need to do is create some app code that will correctly receive the events.

Each event will trigger a request containing a JSON payload sent to your configured Request URL. The Events API docs contain a full description of the shape of this JSON, and the reference for app_mention and the message.channels contain any details specific to each event type.

Your app has to be able to receive and parse this JSON, then send an immediate confirmation response to each event request as described in the Events API docs.

Here's how we might build our code for receiving events:

// Receive event payload to Request URL via HTTP POST
router.post("/", function(req, res, next) {
    // Get event payload
    let payload = req.body;
    // Respond to this event with HTTP 200 status

Now that you've written code to handle an event, you can think about how to respond in a "bot-like" way.

Responding to mentions using the Web API

For a bot, being mentioned is usually the triggering event for a conversation, just as a human will respond when they hear their name. Your app code should use the type field inside the event payload to spot these app_mention events, and to differentiate them from any other events it might receive.

In addition, you don't want to respond to every mention, only the ones that are actually intended to trigger the "tell a joke" flow. To do that, use the text field from the event payload, which contains the text of the message that the mention was contained in. When text mentions the bot and includes the words "tell me a joke", the bot will respond; otherwise it'll just stay quiet.

Here's what the example code might look like with this kind of logic:

router.post("/", function(req, res, next) {
    let payload = req.body;

    if (payload.event.type === "app_mention") {
        if (payload.event.text.includes("tell me a joke")) {
            // Make call to chat.postMessage using bot's token

With the call to chat.postMessage, the first line of the joke is sent:

Knock, knock.

To send this, your app should use that API method with the token you stored earlier. Here's an example request:

POST https://slack.com/api/chat.postMessage
Content-type: application/json
Authorization: Bearer YOUR_BOTS_TOKEN
    "text": "Hello <@UA8RXUPSP>! Knock, knock.",
    "channel": "C123ABC456"

You can read the API method reference for more info on building this request. You can also use the special formatting, attachments, and interactive components available for messages.

So, your bot has uttered those first magical words, and you can assume that the user will reply with the standard "Who's there?" response. Let's find out how to keep the joke going.

Responding to other messages

As we said before, the flow we're describing contains an app_mention event followed by three message events. In order to identify the differences between those three messages, the app logic becomes a bit more complex.

The first thing you need to do is use the type field inside the event payload to look for these message events.

Next, use the text of the message in the event payload to decide which kind of response your bot should make. Again, let's assume the pattern of "knock, knock" jokes β€” the first user response is always "Who's there?", and the second user response is always "____ who?". So, you can check for messages that include these words, and use the right response for each. If you see any messages that don't include either of these phrases, ignore them.

Adding to the code from previous steps, you'll have something like this:

router.post("/", function(req, res, next) {
    let payload = req.body;

    if (payload.event.type === "app_mention") {
        if (payload.event.text.includes("tell me a joke")) {
            // Make call to chat.postMessage using bot's token
    if (payload.event.type === "message") {
        let response_text;
        if (payload.event.text.includes("Who's there?")) {
            response_text = "A bot user";
        if (payload.event.text.includes("Bot user who?")) {
            response_text = "No, I'm a bot user. I don't understand jokes.";
        if (response_text !== undefined) {
            // Make call to chat.postMessage sending response_text using bot's token

Congratulations, your first bot is now chatting! You should now be able to go to the channel you installed the bot into and strike up this conversation with it. Remember to laugh politely when it tells you the punchline.

Your next steps should involve adding more complexity to your bot to make it useful.

Making more complex bots

In the steps above, we made a lot of assumptions for simplicity. For example, we expected that users would respond with a very specific spelling, we assumed a test environment where there were no other conversations happening, and so on.

For a real bot in production, some of these assumptions would break the behavior of the bot. So, let's cover some situations that you should address for your own bots β€” think of these as best practices rather than specific instructions to follow.

Tracking conversations

In our example, we've used a mention as the triggering point for a specific conversation, but you'll notice that your bot will still respond if you skip some of the steps. For example, if you type Who's there?, your bot will respond to this message with A bot user, even if you didn't mention the bot or start at the beginning of the conversation.

A solution to this might involve tracking the beginning of a conversation, the participants involved, and the progress through the flow. For example, when the user first mentions the bot, a database entry is created that identifies that user and the open workflow with them.

As the user progresses through the flow, the database records this, and the user is unable to repeat earlier steps in the conversation (unless that is a desired behavior). Once the workflow is completed, the database entry is also marked as complete, and the bot waits for another mention before starting anew.

Threaded messages

Be aware that a user might choose to reply to your bot's messages in a thread rather than at the channel-level. Your bot will still receive message events for these threaded replies, but you will have to add some extra logic to ensure that your bot responds to the user in the relevant location.

Check out threading messages for more information on how to spot the difference between messages and threaded messages.

Variations in phrasing

Because your bot will be interacting with humans, it's unlikely that you can expect consistent spelling and phrasing across messages from different people that might be trying to invoke the same thing. For example, our example bot used the phrase tell me a joke to trigger the start of the workflow, but at a very basic level, a user might also try typing what's a good joke? or make me laugh.

Your bot can get more complex by broadening the bot's understanding of natural language queries to capture a wider range of potential trigger phrases. Alternatively, you can be more prescriptive about the exact phrasing to use, and provide user education to train correct usage.

Integrating with other services

The real magic of a bot comes when it is connected with external services, providing a seamless conversational interface for them from within Slack. There's a huge range of possibilities for what your bot could do!


Like other APIs and integrations, bot users are free. Unlike regular users, the actions they can perform are somewhat limited. For workspaces on the Free plan, each bot user counts as a separate integration.

API methods for legacy bots

Legacy bot users, and legacy bot tokens, can be used with a restricted set of Web API methods. These methods are shown below.

Methods for legacy bots

Method & DescriptionDescription
Checks API calling code.
Checks API calling code.
Checks authentication & identity.
Checks authentication & identity.
Gets information about a bot user.
Gets information about a bot user.
Registers a new Call.
Registers a new Call.
Ends a Call.
Ends a Call.
Returns information about a Call.
Returns information about a Call.
Registers new participants added to a Call.
Registers new participants added to a Call.
Registers participants removed from a Call.
Registers participants removed from a Call.
Updates information about a Call.
Updates information about a Call.