Receiving Slash Commands from Slack

A Slash Command allows users to invoke your app by typing a message directly into their Slack. You can configure Slash Commands as entry points to fire off actions in your app and respond back to the user with contextual information. To learn more read through this guide from Slack.

Let's walk through how to set up Slash Commands with your Slack App in Fusebit. First, let's set up configure your Connector.

Configure your Connector

In Fusebit, update your ConnectorConnector - A connector is the package from Fusebit that manages the relationship between one or more integrations and a specific service. One of the most common types of connector is an OAuth connector, which takes care of the OAuth negotiation between your customers and the service you're integrating, so that you don't have to! configurations:

  1. Update the Bot Token Scope to include commands
  2. Define an Integration ID that will be used to handle both the Acknowledgment & Message Responses
Slack Connector Configuration to handle InteractivitySlack Connector Configuration to handle Interactivity

Slack Connector Configuration to handle Interactivity

Next, in the Slack App Dashboard, update your Slack App as well:

  1. In the dashboard for your app, navigate to Features > OAuth & Permissions > Scopes and add the commands OAuth scope.
Slack App Dashboard - OAuth ScopesSlack App Dashboard - OAuth Scopes

Slack App Dashboard - OAuth Scopes

For your app, you will also have to enable "Slash Commands" or "Interactivity & Shortcuts" from this dashboard based on your apps needs. It's fairly straightforward to do, and you can also follow along in the guide's available from Slack.

Set up your Integration

There are two main components to handling interactivity:

  • Acknowledgement Response: Must happen within 3000 ms or the user will get a timeout.
    In the screenshot below, this is the "⏳ Running..." message.
  • Message Response: Can take longer and must be targeted back to the original Slack Message.
    In the screenshot below, this is the "Hey shehzad, thank you for leaving kudos for @matthew!" message

The Integration ID you defined in your Connector will be responsible for Acknowledgement & Message Responses. Let's walk through each of the different interactions you will be able to handle in your integration, starting with Slash Commands.

Interactivity Example: Slash CommandInteractivity Example: Slash Command

Interactivity Example: Slash Command

Acknowledgement Response

As mentioned above, Slack requires all incoming interactivity requests to receive an HTTP 200 Acknowledgement within 3000 ms, you must also send back a custom message that will be displayed to the user.

Fusebit takes care of this for you, but you must define the following endpoint in your integration.

// Acknolwedgement Response
router.post('/api/fusebit/webhook/event/immediate-response', async (ctx) => {
  ctx.body = {
    text: `:hourglass_flowing_sand: Running...`,
    response_type: 'ephemeral',
  };
});

🚧

Acknowledgement Responses Timeout

While you can customize the message sent back in Acknowledgement Responses, it is highly recommended you respond back with static text such as 'Looking into this' or 'Command Received!'. If the response takes longer than 3000ms, the Slack user will receive a 'timeout' response and the interactivity will fail.

Message Response

In addition to the static immediate 'Acknowledgement' Response, you will want to respond to the message with contextual data based on what the User has requested.

πŸ“˜

Finding the Tenant ID from Slack

Most incoming Requests include a response_url that is used to respond back directly without requiring any authentication. The slackClient object provided by Fusebit uses the officially recommended @slack/webhook package to facilitate this via theintegration.webhook.send method.

To find the associated Tenant ID and make an authenticated call instead, you can use the integration.webhook.searchInstalls method using the tags received (e.g. user_id, team_id) in the request body.

To respond back to the message, you can leverage the Fusebit's Event Handler to receive and respond back to the message:

// Message Response
integration.event.on('/:componentName/webhook/slash-command/:slashCommand', async (ctx) => {

  const user_name = ctx.req.body.data.user_name;
  const slash_body = ctx.req.body.data.text
  const kudos_receiver = slash_body.replace('kudos ','');
  
  // webhook.send responds using the response_url provided by Slack in the webhook payload
  await integration.webhook.send(ctx, {text: `Hey ${user_name}, thank you for leaving kudos for ${kudos_receiver}!`});

});
integration.event.on('/:componentName/webhook/slash-command/:slashCommand', async (ctx) => {

  const user_name = ctx.req.body.data.user_name;
  const slash_body = ctx.req.body.data.text
  const kudos_receiver = slash_body.replace('kudos ', '');
  const { team_id, user_id, api_app_id: app_id, channel_id } = ctx.req.body.data;

  try {
    // Find Install based on the Tags
    const installs = await integration.webhook.searchInstalls(ctx, 'slackConnector', {app_id,team_id,user_id});
    const slackClient = await integration.service.getSdk(ctx, 'slackConnector', installs[0].id);
    
    await slackClient.chat.postMessage({
      text: `Hey ${user_name}, thank you for leaving kudos for ${kudos_receiver}!`,
      channel: channel_id,
    });

  } catch (error) {
    // Detect if the error is coming because no Installs were returned
    if (error.statusCode === 404) {
      await integration.webhook.send(ctx, { text: 'User is not authorized, please re-install the Slack Integration: INSERT_URL' });
    } else {
      // Something else failed, log the error and inform the user
      console.log(error.message);
      await integration.webhook.send(ctx, { text: 'Something went wrong!' });
    }
  }

});

For all incoming messages, the request body will consist of two items:

  • Slack Interactions Payload under the data object.
  • Fusebit Event Metadata which includes items such as related Integration ID, related Installation IDs etc.

Here is an example of an incoming Request Body from a Slash Command:

{
  data: {
    token: 'LVGaG1ijm6mcT4ZdxJ8MawUz',
    team_id: 'T02A14HFYDP',
    team_domain: 'shehzadakbar',
    channel_id: 'D03FRNN3U93',
    channel_name: 'general',
    user_id: 'U03FN160NLE',
    user_name: 'shehzad',
    command: '/fusebot',
    text: 'kudos @matthew',
    api_app_id: 'A03FCRX58P2',
    is_enterprise_install: 'false',
    response_url: 'https://hooks.slack.com/commands/T02A14HFYDP/3570255915379/l28xBKVZyi2nqox7k4qOBul7',
    trigger_id: '3570274972370.2341153542465.fbcced0ce22255e0ea000b692493b143'
  },
  eventType: 'slash-command/shehzad',
  entityId: 'SlashCommandsDocs',
  webhookEventId: 'webhook/MySalesforceIntegration/T02A14HFYDP/A03FCRX58P2',
  webhookAuthId: 'T02A14HFYDP/A03FCRX58P2',
  installIds: [
    'ins-240139fbe8e2115e3f59b9b9ac9a6c59',
    'ins-2aeddde7c09dfae20550c177e1b5e9b6'
  ]
}

πŸ‘

Good Job!

Now your Slack App can handle and respond to Slash Commands!

In our next section, we will walk through how to configure your app for Shortcuts, an advanced UI-based interaction that you can offer to users.


Did this page help you?