Back to blog
March 24, 2025 · LithoBlocks Team

How to Handle Slack Interactive Message Actions in Make

A step-by-step guide to wiring Slack button clicks to Make scenarios: Slack app setup, payload parsing, action_id routing, and the 3-second rule.

#slack#make#automation#block kit#integrations

Sending rich Slack messages with buttons is straightforward. Actually handling what happens when someone clicks a button is where most teams get stuck. This guide walks through the full setup: creating a Slack app, configuring interactivity, receiving and parsing the payload in Make, and responding correctly.

How Slack interactive actions work

When a user clicks a button in a Slack message, Slack sends an HTTP POST request to a URL you configure. The payload is a URL-encoded JSON string containing everything about the interaction: who clicked, which message, which button, and the original message content.

Your endpoint has 3 seconds to respond with HTTP 200. If it doesn’t, Slack shows the user an error and retries. More on this below.

Step 1: Create a Slack app

If you don’t already have one:

  1. Go to api.slack.com/apps and click Create New App
  2. Choose From scratch, give it a name, and select your workspace
  3. Under OAuth & Permissions, add these bot token scopes: chat:write, chat:write.public
  4. Install the app to your workspace and copy the Bot User OAuth Token: you’ll need it to send messages

Step 2: Enable interactivity

In your app settings, go to Interactivity & Shortcuts and toggle it on. Set the Request URL to your Make webhook URL.

This is the URL Slack will POST to every time a user interacts with any message your app sends. You’ll route to different logic based on the action_id in the payload.

To get your Make webhook URL: create a new scenario, add a Webhooks → Custom webhook module as the trigger, and copy the URL it generates. You’ll need to run the scenario once so Make can capture a sample payload to infer the data structure.

Step 3: Add action_ids to your buttons

In your Block Kit message, every interactive element needs an action_id. This is how you’ll tell Make (and your logic) which button was clicked.

{
  "type": "actions",
  "elements": [
    {
      "type": "button",
      "text": { "type": "plain_text", "text": "Approve" },
      "action_id": "approve_request",
      "value": "request_id_123",
      "style": "primary"
    },
    {
      "type": "button",
      "text": { "type": "plain_text", "text": "Reject" },
      "action_id": "reject_request",
      "value": "request_id_123",
      "style": "danger"
    }
  ]
}

Use descriptive action_id values: you’ll be filtering on these in Make. The value field is where you carry any identifier you’ll need to look up the relevant record on the other end.

Step 4: Parse the payload in Make

When Slack sends the interaction, the body is application/x-www-form-urlencoded with a single payload key whose value is a URL-encoded JSON string.

In your Make webhook module, map payload to a Parse JSON module. The structure you’ll get looks like this (simplified):

{
  "type": "block_actions",
  "user": { "id": "U123456", "name": "jane" },
  "actions": [
    {
      "action_id": "approve_request",
      "value": "request_id_123",
      "type": "button"
    }
  ],
  "message": { ... },
  "channel": { "id": "C123456" },
  "response_url": "https://hooks.slack.com/actions/..."
}

Key fields:

  • actions[0].action_id — which button was clicked
  • actions[0].value — the value you set on the button
  • user.id — who clicked it
  • response_url — a URL you can POST to in order to update the original message (valid for 30 minutes)
  • channel.id — the channel the message is in

Step 5: Route by action_id

Add a Router module after the JSON parser and create a path for each action_id you handle. Each path’s filter condition is: actions[0].action_id equals approve_request (or whatever your action_id is).

From there, each path can do whatever it needs: update a database, call an API, send a follow-up message.

Step 6: Respond within 3 seconds

This is where Make scenarios often fail. Make’s webhook module automatically returns 200 to Slack when it receives the request: but your scenario may take longer than 3 seconds to finish. Slack doesn’t care about that; it cares about the initial 200 response, which Make handles.

However, if you want to update the original message to show that the action was handled (highly recommended), use the response_url from the payload:

  1. Add an HTTP → Make a request module
  2. Method: POST
  3. URL: {{payload.response_url}}
  4. Body type: application/json
  5. Body: a Block Kit message payload with "replace_original": true

This replaces the original message with an updated version, for example showing ”✅ Approved by Jane” instead of the original Approve/Reject buttons. Do this as soon as you’ve processed the action; the response_url is only valid for 30 minutes.

The simpler path: LithoBlocks

The flow above works, but it requires Slack app configuration, webhook setup, action_id routing, and manual payload parsing every time you add a new interactive message type.

LithoBlocks handles the Slack app layer and the message template management. You build messages in the visual editor (including interactive buttons with action_ids), trigger them via a webhook from Make, and handle the responses through a simpler routing interface, without touching Block Kit JSON or writing custom payload parsers.

For teams building more than one or two interactive flows, the setup overhead of the manual approach adds up quickly.


LithoBlocks makes interactive Slack messages manageable without Slack app configuration overhead. See how it works →

// try lithoblocks

Stop hand-writing Block Kit.

Build Slack message templates visually. Send them with one REST call. Update them after a click with a built-in action archive.