Go to Slack

Enabling interactivity with Slash Commands

The rundown
Read this if:You're still experimenting, prototyping, and exploring.
Read first:An overview of app interactivity

What are Slash Commands?

Slash Commands allow users to invoke your app by typing a string into the message composer box.

A submitted Slash Command will cause a payload of data to be sent from Slack to the associated app. The app can then respond in whatever way it wants using the context provided by that payload.

These commands are the entry points for complex workflows, integrations with external services, or even just simple message responses. They're the knock at your app's front door that could be the start of a great conversation.

Some commands like /topic and /remind are built into Slack (here's a list of all of them) but others are created by developers like you for use with Slack Apps.

When part of an app, they can be easily installed for your workspace as an single workspace app or shared with the world, distributed to other workspaces via the App Directory.

Slash Commands require a particular invocation structure that makes them less universally usable compared to other app entry points. Make sure you understand your app's audience before implementation.

Understanding the structure of Slash Commands

Let's look at an example Slash Command, for a simple app that stores a list of to-do tasks:

/todo ask @crushermd to bake a birthday cake for @worf in #d-social

Here's the structure:

  • /todo - this is the command, the part that tells Slack to treat it as a Slash Command and where to route it. You'll define yours below.
  • ask @crushermd to bake a birthday cake for @worf in #d-social - this is the text portion, it includes everything after the first space following the command. It is treated as a single parameter that is passed to the app that owns the command (we'll discuss this more below).

We want to make sure that birthday cake gets baked, so read on to find out how to setup commands for your apps, and how to handle and respond to them.


Getting Started with Slash Commands

In order to get Slash Commands up and running with your app, you'll have to create the command itself, then prepare your app to be able to handle the interaction flow. We'll describe that flow in more detail in the steps below, but the basic pattern is:

  • A user in Slack types in the message box with the command, and submits it.
  • A payload is sent via an HTTP POST request to your app.
  • Your app responds in some way.

That's all pretty orderly, so let's look at the recipe for making a great Slash Command.

1. Creating a Slash Command

Creating a command is really simple, you just need two things - a Slack App and the name of your new command. If you don't already have a Slack App, click the following button to create one:

Create your Slack app

Now let's get to actually creating that command. First, head to your app's management dashboard, and then click the Slash Commands feature in the navigation menu.

You'll be presented with a button marked Create New Command, and when you click on it, you'll see a screen where you'll be asked to define your new Slash Command:

  • Command - the name of command, the actual string that users will type to trigger a world of magic. Bear in mind the naming advice below when you pick this.
  • Request URL - the URL we'll send a payload to, when the command is invoked by a user. You'll want to use a URL that you can setup to receive these payloads as we'll describe later in this doc. If public distribution is active for your app, this needs to be an HTTPS URL (and self-signed certificates are not allowed). If you're just building an app solely for your own workspace, it can be plain HTTP.
  • Short Description - exactly what it sounds like, a short description of what your command does.
  • Usage Hint - displayed to users when they try to invoke the command, so if you have any parameters that can be used with your command, we recommend showing them here. You'll see a preview of the autocomplete entry where this hint is displayed, so make sure you're keeping this hint brief enough not to get truncated.
  • Escape channels, users, and links sent to your app - turning this on will modify the parameters sent with a command by a user. It will wrap URLs in angle brackets (ie. <http://example.com>) and it will translate channel or user mentions into their correlated IDs - so if a user invoked your command like this:

    /todo ask @crushermd to bake a birthday cake for @worf in #d-social
    

    You'll receive the following in the sent data payload:

    ask <@U012ABCDEF> to bake a birthday cake for <@U345GHIJKL> in <#C012ABCDE>
    

    If disabled, the payload will just repeat the plain text:

    ask @crushermd to bake a birthday cake for @worf in #d-social
    

    While your eyes might take less offense to the second example, in that case you'd have to resolve those plain-text names yourself - using users.list or conversations.list - if you planned to use any Slack API in your response to the command.

    We recommend that you enable this feature if you expect to receive user or channel mentions in the command text.

Escaped usernames may include the plain text username as well, with a bar (|) separator (like this <@U012ABCDEF|worf>).
However, as we are phasing out usernames, your app should only account for the possible presence of that plain text username and separator, but not rely on them.

A slight digression about naming your Slash Command

Consider your command's name carefully. Slash Commands are not namespaced.

This means multiple commands may occupy the same name. If it happens and a user tries to invoke the command, Slack will always invoke the one that was installed most recently. It's an important thing to consider especially if you're planning to distribute your app.

So when you're picking a command name, you will want to avoid terms that are generic and therefore likely to be duplicated. On the other hand, you don't want the command to be too complicated for users to easily remember.

In essence, a great command is descriptive and simple but also unique. Naming it after your service is often a good idea.

Once you've created a truly unforgettable command, any channel or workspace where your app is installed will immediately be able to start using it, so let's learn what to do when a user types one of your app's commands.

2. Preparing your app to receive Commands

When a slash command is invoked, Slack sends an HTTP POST to the Request URL you specified above. This request contains a data payload describing the source command and who invoked it, like a really detailed knock at the door.

For example, imagine a workspace at example.slack.com installed an app with a command called /weather. If someone on that workspace types /weather 94070 in their #test channel and submits it, the following payload would be sent to the app:

token=gIkuvaNzQIHg97ATvDxqgjtO
&team_id=T0001
&team_domain=example
&enterprise_id=E0001
&enterprise_name=Globular%20Construct%20Inc
&channel_id=C2147483705
&channel_name=test
&user_id=U2147483697
&user_name=Steve
&command=/weather
&text=94070
&response_url=https://hooks.slack.com/commands/1234/5678
&trigger_id=13345224609.738474920.8088930838d88f008e0

This data will be sent with a Content-type header set as application/x-www-form-urlencoded. Here are details of some, but not all, of the important fields you might see in this payload:

Parameter Description
token This is a verification token, a deprecated feature that you shouldn't use any more. It was used to verify that requests were legitimately being sent by Slack to your app, but you should use the signed secrets functionality to do this instead.
command The command that was typed in to trigger this request. This value can be useful if you want to use a single Request URL to service multiple Slash Commands, as it lets you tell them apart.
text This is the part of the Slash Command after the command itself, and it can contain absolutely anything that the user might decide to type. It is common to use this text parameter to provide extra context for the command.

You can prompt users to adhere to a particular format by showing them in the Usage Hint field when creating a command.
response_url A temporary webhook URL that you can use to generate messages responses.
trigger_id A short-lived ID that will let your app open a modal.
user_id The ID of the user who triggered the command.
user_name The plain text name of the user who triggered the command. As above, do not rely on this field as it is being phased out, use the user_id instead.
team_id, enterprise_id, channel_id, etc. These IDs provide context about where the user was in Slack when they triggered your app's command (eg. which workspace, Enterprise Grid, or channel). You may need these IDs for your command response.

The various accompanying *_name values provide you with the plain text names for these IDs, but as always you should only rely on the IDs as the names might change arbitrarily.

We'll include enterprise_id and enterprise_name parameters on command invocations when the executing workspace is part of an Enterprise Grid.

If public distribution is active for your app, Slack will occasionally send your command's request URL a simple POST request to verify the server's SSL certificate. These requests will include a parameter ssl_check set to 1 and a token parameter. The token value corresponds to the verification token registered with your app's slash command. See the token field above for more information on validating verification tokens. Mostly, you may ignore these requests, but please do confirm receipt as below.

This payload is like getting all the ingredients to bake a really nice cake, so let's take a look at the recipe.

3. Responding to Commands

There are three main ingredients in the response cake:

  1. Acknowledge your receipt of the payload.
  2. Do something useful in response right away.
  3. Do something useful in response later.

The first is like the cake itself, a required minimum, but the other two are like optional icing and toppings. We'll examine this more closely and get our fingers sticky.

Confirming receipt

This is the step which lets Slack, and therefore the user, know that the command was successfully received by the app, regardless of what the app intends to do.

Your app can do this simply by sending back an empty HTTP 200 response to the original request.

If you don't do this, the user will be shown an error message that indicates that the slash command didn't work - not a great experience for the user, so you should always acknowledge receipt (unless of course you didn't receive the command, but then you wouldn't know not to respond, and now we've fallen into a logical paradox).

This confirmation must be received by Slack within 3000 milliseconds of the original request being sent, otherwise a Timeout was reached will be displayed to the user. If you couldn't verify the request payload, your app should return an error instead and ignore the request.

The HTTP 200 response doesn't have to be empty however, it can contain other useful stuff - a plain cake isn't all that tasty, so maybe we should add some icing.

Sending an immediate response

As mentioned, you can include more substantive info in the body of your HTTP 200 response. In fact, you can use any of the complex formatting or Block Kit layout options that are available when sending any message.

You can include this message either as plain text in the response body:

It's 80 degrees right now.

Or as a JSON payload in the response body, with a Content-type header of application/json:

{
    "blocks": [
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": "*It's 80 degrees right now.*"
            }
        },
        {
            "type": "section",
            "text": {
                "type": "mrkdwn",
                "text": "Partly cloudy today and tomorrow"
            }
        }
    ]
}

These message responses can even include interactive elements like buttons or menus to allow users to interact more and keep the workflow active. Read our guide to composing messages to explore the full range of possibilities.

Message Visibility

There's one special feature to response messages - when responding with a JSON payload you can directly control whether the message will be visible only to the user who triggered the command (we call these ephemeral messages), or visible to all members of the channel where the command was triggered.

The response_type parameter in the JSON payload controls this visibility, by default it is set to ephemeral, but you can specify a value of in_channel to post the response into the channel, like this:

{
    "response_type": "in_channel",
    "text": "It's 80 degrees right now."
}

When the response_type is in_channel, both the response message and the initial Slash Command typed by the user will be shared in the channel:

Example of a command in channel response

For the best clarity of intent, we recommend always declaring your intended response_type, even if you wish to use the default ephemeral value.

Now that you've added some response icing, this cake is looking pretty tasty. But is there anything else can you do to respond?

Other responses

If you need to respond outside of the 3 second window provided by the request responses above, you still have plenty of options for keeping the workflow alive.

Read our guide to responding to user interactions. There we'll explain how you can use fields like response_url or trigger_id from your Slash Command payload to open modals and send messages.

We also explain all the multitude of other ways you can top this cake.

Sending error responses

There are going to be times when you need to let the user know that something went wrong - perhaps the user supplied an incorrect text parameter alongside the command, or maybe there was a failure in an API being used to generate the command response.

It would be tempting in this case to return an HTTP 500 response to the initial command, but this isn't the right approach. The status code returned as a response to the command should only be used to indicate whether or not the request URL successfully received the data payload - while an error might have occurred in processing and responding to that payload, the communication itself was still successful.

Instead, you should continue to follow the above instructions to send either an response message back via the HTTP request or using the request_url. In that response messages, communicate the error back to the user:

{
  "response_type": "ephemeral",
  "text": "Sorry, that didn't work. Please try again."
}

Best Practices

  • If you're not ready to respond to an incoming command but still want to acknowledge the user's action by having their slash command displayed within the channel, respond to your URL's invocation with a simplified JSON response containing only the response_type field set to in_channel: {"response_type": "in_channel"}.
  • If your command doesn't need to post anything back (either privately or publicly), respond with an empty HTTP 200 response. You should use this only if the nature of your command makes it obvious that no response is necessary or desired. Even a simple "Got it!" ephemeral response is better than nothing.
  • Help your users understand how to use your command. Provide a help action that explains your command's usage. If your slash command was /please, you should provide a response to /please help that lists the other actions available.
  • Keep track of the validation token Slack gives you when the command is created. Always validate the token field in an incoming slash command request has been issued to you by Slack.
  • Turn on escaping for usernames, channels, and links by flipping the toggle in your slash command's configuration dialog. Always work with user IDs and channel IDs.
  • Give your command a descriptive and unique name to avoid conflicts with other apps.