You must enable javascript in order to use Slack. You can do this in your browser settings.
Go to Slack

Slash Commands

The rundown
Read this if:You're still experimenting, prototyping, and exploring.
Read first:Managing Slack apps
Read next:Introducing Block Kit

Slash Commands let users trigger an interaction with your app directly from the message box in Slack.

A slash command at work!

What are Slash Commands?

Slash Commands are initiated from the message box in Slack, but they aren't messages. A submitted Slash Command will cause a payload of data to be sent from Slack to an app, allowing the app to respond in whatever way it wants.

These commands are the starting point 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 internal integration or shared with the world, distributed to other workspaces via the App Directory.

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 Slash Command 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 data payload is sent via an HTTP POST request to the URL configured for that command in your app.
  • The app responds in some way.

That's all pretty orderly, so let's go and 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 settings page, 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 the data 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 internal integration 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. <>) 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 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:


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 URL that you can use, as we'll show later, to respond to the command.
trigger_id If you need to respond to the command by opening a dialog, you'll need this trigger ID to get it to work. You can use this ID with up to 3000ms after this data payload is sent.
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 activated 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. Confirm 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 attachment fields 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.

Default command response - plain text, visible only to user who issued the command

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

    "text": "It's 80 degrees right now.",
    "attachments": [
            "text":"Partly cloudy today and tomorrow"

Example of a command ephemeral response

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.",
    "attachments": [
            "text":"Partly cloudy today and tomorrow"

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 what about when you can't respond right away?

Sending delayed responses

The process of making a cake is pretty complex - there are lots of different things to prepare at different times, and you might have your base already baked while still creating a complex topping.

Similarly, dealing with APIs isn't instant - when you receive the command data payload, your app might need to go off and query another API, and then fetch something from a database, or maybe just prompt the user for more information and await their response.

All these things take time, and when they're done, you might be outside of that 3000ms window for responding to the original request. Don't worry though, you still have options.

Back when you received the data payload after the command was invoked, there will have been a response_url field included. This URL can be used to send responses after the 3000ms window has closed.

To use this response_url:

  • Construct an HTTP POST request with a JSON body that has the exact same structure as the immediate response messages above.
  • Set a Content-type header of application/json.
  • Send it to the response_url.

As with immediate response messages, you can include the response_type field. However, when you use a value of in_channel with this delayed method, the original text that invoked the command is not included.

The response_url can be used up to 5 times, within 30 minutes of the command being invoked. Just like a cake left around for 30 minutes will definitely be eaten, don't leave it too late.

One important note about this delayed response method is you must still send that initial HTTP 200 response within 3000ms. As before, that response can be empty, but we recommend that it contain a useful message, even if your actual response won't be sent until a few seconds later.

A good idea is send an immediate confirmation message to the user that tells them that their command was received and the response is being processed, and then use response_url to post that processed response later.

If you need more than 30 minutes to create your response (maybe the workflow involves a question and answer service where the response is actually written by a human), you should consider either creating a Bot User, or using the Web API to respond via a method like chat.postMessage.

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 immediate response or delayed response message, and use a JSON payload to communicate the error back to the user as an ephemeral message:

  "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.
  • Be aware of the limitations for how many attachments you can include with a message.
  • 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.
  • If you're using message buttons or attachments, be sure and follow our guidelines.

Consult our Slash Commands Style Guide for further tips!

Extra info for Enterprise Grid users

Be on the look out for invocations from users on workspaces that haven't installed your app. As part of Enterprise Shared Channels, you may encounter users from another workspace. While they won't be listed in users.list, you can look up limited information by ID using