IntegrationsIntegrations

How to Test Slack Webhooks Locally

What Webhooks Does Slack Send?

Slack sends webhooks through several mechanisms: the Events API for real-time events, slash command payloads, interactive component payloads (buttons, menus, modals), and shortcut invocations. Each has a slightly different format but they all arrive as HTTP POST requests to your configured URL.

Events API payloads include events like message, app_mention, member_joined_channel, reaction_added, and file_shared. These are wrapped in an envelope with a type field (event_callback), a team_id, and the actual event in an event object. Slack also sends a url_verification challenge when you first configure your endpoint.

Slash command payloads arrive as application/x-www-form-urlencoded data (not JSON) and include the command text, user info, channel info, and a response_url for sending follow-up messages. Interactive component payloads are similar but include a payload field containing JSON.

Configuring Slack with ReqPour

In the Slack API dashboard (api.slack.com/apps), go to your app's settings. For the Events API, navigate to Event Subscriptions and enter your ReqPour URL as the Request URL. Slack sends a verification challenge — a JSON POST with type: "url_verification" and a challenge string that your server must echo back.

For slash commands, go to Slash Commands and set the Request URL to your ReqPour endpoint. For interactive components, go to Interactivity & Shortcuts and set the Request URL there. Each can point to different paths on your ReqPour endpoint, like https://abc123.reqpour.com/slack/events and https://abc123.reqpour.com/slack/commands.

Start the ReqPour relay to forward these requests to your local server:

bash
npx reqpour relay --to http://localhost:3000

This forwards all requests, preserving the path structure so /slack/events and /slack/commands route correctly on your local server.

Handling the URL Verification Challenge

When you first set up the Events API, Slack sends a challenge request that your server must respond to:

javascript
app.post('/slack/events', express.json(), (req, res) => {
  // Handle URL verification challenge
  if (req.body.type === 'url_verification') {
    return res.json({ challenge: req.body.challenge });
  }

// Verify the request is from Slack // (use @slack/events-api or verify manually)

const event = req.body.event;

if (event.type === 'app_mention') { console.log(Mentioned by ${event.user} in ${event.channel}); // Respond via Web API, not the webhook response }

res.status(200).send(); }); ```

Make sure your ReqPour relay is running when you configure the Events API URL so the challenge response flows back to Slack. The ReqPour dashboard will show the challenge request and your server's response, which is helpful for debugging if verification fails.

Processing Slash Commands and Interactive Components

Slash commands arrive as form-encoded data. Parse them accordingly:

javascript
app.post('/slack/commands',
  express.urlencoded({ extended: true }),
  (req, res) => {
    const { command, text, user_id, response_url } = req.body;

if (command === '/deploy') { // Respond immediately (within 3 seconds) res.json({ response_type: 'in_channel', text: Deployment started by <@${user_id}>: ${text}, });

// Do the actual work asynchronously startDeploy(text, response_url); } } ); ```

Interactive component payloads contain a payload field that is a JSON string. Parse it to get the action details, user info, and response URL. When inspecting these in the ReqPour dashboard, look at the form data view to see the raw payload, then use the parsed view to examine the JSON structure inside.

Slack's 3-second response timeout is strict. For operations that take longer, respond immediately with a loading message and use the response_url to update it later.

Slack Webhook Security and Best Practices

Slack signs requests with a shared secret. Verify the X-Slack-Signature header by computing an HMAC-SHA256 of v0:timestamp:body using your signing secret. The official @slack/events-api and @slack/bolt libraries handle this automatically.

During development with ReqPour, you can inspect the signature headers in the dashboard to understand the verification process. If your verification is failing, compare the timestamp and computed hash in your handler with the values visible in the ReqPour request inspector.

Slack retries webhook deliveries up to 3 times with exponential backoff. Your handler should respond with a 200 status quickly, even if processing takes time. Use the ReqPour dashboard to monitor response times and catch handlers that are too slow.

When developing Slack apps, you will often need to test different user interactions — button clicks, menu selections, modal submissions. ReqPour's replay feature lets you re-send any captured interaction payload, so you can iterate on your handler without navigating through the Slack UI each time.

Get started with ReqPour

Catch, inspect, and relay webhooks to localhost. Free to start, $3/mo for Pro.