How to Test Slack Webhooks
When developers talk about "Slack webhooks," they are usually referring to one of two completely different things: Incoming Webhooks or the Events API. Understanding the difference is the first step to building and testing a Slack integration successfully.
Incoming Webhooks vs Events API
Incoming Webhooks are for sending data into Slack. Your application makes an HTTP POST request to a specific Slack URL, and Slack posts a message in a channel. Because you are the one sending the request, testing them just requires making a curl call or using a tool like Postman to ensure your JSON message block is formatted correctly.
The Events API (often called outbound webhooks) is for getting data out of Slack. When an event happens in your workspace—like a new user joining, an app being uninstalled, or a specific keyword being mentioned—Slack sends an HTTP POST request to your server. This requires a dedicated webhook endpoint to receive the data.
This guide focuses on testing the Events API, as it is the significantly more complex half of the equation.
The Slack URL verification handshake
Stop reading raw JSON
Payloader shows you what your Slack webhook actually did — in plain English. See the event, amount, status, and more at a glance.
Start free trial →Before Slack will send any events to your server, they force you to prove that you actually control the endpoint URL. This is called the URL Verification handshake.
When you paste your endpoint URL into the Slack App configuration dashboard, Slack immediately sends an HTTP POST request to it. The payload looks like this:
{
"token": "Jhj5dZrHLZeIglZXYZ...",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
Your server must respond with an HTTP 200 OK and return the exact challenge string in the body of the response. If you fail this handshake, Slack will refuse to save your URL, and you cannot proceed.
Setting up a test environment
Because of the URL verification handshake, testing Slack events locally requires immediate routing.
You can use a tool like Payloader to manage this workflow:
- Create an endpoint URL in Payloader and set up Webhook Forwarding to point to your local development server.
- Paste the Payloader URL into your Slack App's "Event Subscriptions" page.
- Ensure your local server is running and configured to echo back the
challengeparameter.
Slack will send the verification request. Payloader will catch it and forward it to your local machine, your machine will respond with the challenge string, and the handshake will complete successfully.
Inspecting event payloads
Once verified, you can subscribe to specific workspace events. If you subscribe to message.channels, Slack will send a webhook every time a message is posted in a public channel.
These payloads are nested inside an event wrapper object:
{
"token": "Z26uF5LXYZ...",
"team_id": "T061EG9R6",
"api_app_id": "A0FFV41KK",
"event": {
"type": "message",
"channel": "C024BE91L",
"user": "U2147483697",
"text": "Hello world",
"ts": "1355517523.000005"
},
"type": "event_callback",
"event_id": "Ev08MF2T62",
"event_time": 1530208280
}
Instead of manually parsing this structure in your terminal, Payloader automatically recognizes the Slack Events API format. It extracts the event.type, the user, and the text, providing a clean summary of the action that occurred.
Verifying requests from Slack
Slack no longer relies on the simple verification token found in older payloads. Modern Slack apps use a cryptographic signature passed in the X-Slack-Signature HTTP header.
To verify a request:
- Retrieve the
X-Slack-Request-Timestampheader. Verify it is within 5 minutes of your server's current time to prevent replay attacks. - Concatenate the version number ("v0"), the timestamp, and the raw request body, separated by colons (e.g.,
v0:1531420618:{"type":"event_callback"...}). - Hash this string using HMAC-SHA256 and your app's Signing Secret.
- Compare your hash to the
X-Slack-Signatureheader.
If your application modifies the raw JSON body (like stripping whitespace) before generating the hash, the signature verification will fail. Capturing the raw, unparsed webhook in Payloader allows you to test your hashing logic against the exact bytes Slack sent.