Skip to content
newThe webhook.co MCP server is live — turn any webhook into an agent event. Read the docs
test locally

Test Slack webhooks locally

Slack's Events API won't even save your Request URL until something on the other end answers a challenge. Clear that, and Slack's remaining rules are mostly about speed: three seconds to answer, or the same event comes back three more times.

The loop

Create an endpoint and it prints a permanent ingest URL. Everything sent there is captured whole — headers, body, the exact bytes — before anything else happens. Stream those events to a port on your machine, and replay any one of them as often as you like while you fix the handler. Forwarding runs from your own machine, so it isn't a billable delivery.

wbhkslack
$ wbhk endpoints create slack-dev
https://wbhk.my/whep_…
$ wbhk listen <endpoint-id> --forward http://localhost:3000/webhooks
$ wbhk replay <event-id> --forward http://localhost:3000/webhooks

What's different about Slack

Finish typing a Request URL into Event Subscriptions and Slack immediately POSTs a url_verification body carrying a challenge string; the form refuses to save until your endpoint answers 200 with that same string echoed back. A capture-everything tunnel that acknowledges with an empty body fails the check, and you never get past the form. webhook.co's ingest recognizes the handshake, echoes the challenge, and files nothing, so the green check mark appears and your event list stays free of setup noise.

Where the URL goes

Your app's settings live at api.slack.com/apps. Open the app, find Event Subscriptions, and flip the toggle on; a Request URL field appears, and that's where the ingest URL goes. Slack fires its challenge the moment you stop typing, and a green check mark means it took. If your endpoint was slow to wake and the first attempt timed out, the Retry button re-runs it. Slack also treats Request URLs as case-sensitive.

Slack documents no send-a-test-event control and no delivery log to redeliver from. The one request you can trigger on demand is the handshake, via that Retry button. Everything else means doing the real thing in a workspace: mention the app, post in a channel it watches, react to a message. Nothing reaches you until the Request URL clears its handshake, so get the green check mark first.

What Slack sends

Identifiers are lowercase and underscore-separated, shaped object then action. Messages are the exception worth knowing: instead of a single message event there are dot-suffixed subscriptions per conversation type, so a DM and a public channel post are separate subscriptions.

  • app_mention
  • message.channels
  • message.im
  • reaction_added
  • member_joined_channel
  • team_join

Worth knowing first

Three seconds, then three retries

Slack wants a 2xx inside three seconds. Miss it and the attempt counts as failed, after which Slack retries nearly immediately, then after a minute, then after five. Each attempt carries x-slack-retry-num and x-slack-retry-reason, whose documented values include http_timeout, too_many_redirects and ssl_error. A non-200 carrying x-slack-no-retry: 1 tells Slack to abandon that one event.

Slack can switch you off

Cross more than 95% failed delivery attempts inside a 60-minute window and Slack temporarily disables the app's event subscriptions. The app's creator and owner get an email about it, and turning subscriptions back on is a manual trip through Slack app management. Apps taking fewer than 1,000 events an hour are exempt from the automatic disable.

Duplicates are your problem

Slack's docs never commit to a delivery model, so treat the retry schedule as your duplicate story: a 2xx that arrives late earns you the same event twice. The outer wrapper carries an event_id that Slack documents as globally unique across all workspaces. It is the obvious dedup key, though Slack never nominates it as one.

A ceiling on hourly deliveries

Deliveries top out at 30,000 per workspace per app per 60 minutes. Past the line Slack stops delivering and sends an app_rate_limited event for each minute you stay throttled; what becomes of the events above the cap is left unstated. Unlikely to bite in development, unpleasant to meet later.

Signature checking is handled for you once the secret is registered — you can also check a captured signature by hand in the signature verifier.

Slack webhooks: common questions

Why won't Slack save my Event Subscriptions Request URL?

Slack posts a challenge to the URL the instant you finish typing it, and refuses to save the form until your endpoint replies with a 200 and that same challenge value. webhook.co answers that handshake for you, so the check mark appears without you writing a line of handler code.

Does Slack have a way to send a test webhook event?

Not one that Slack documents. Slack's Events API docs describe no sample-event control and no delivery log to redeliver from, so the only request you can fire on demand is the URL verification retry. For a real payload, perform the action in a workspace and inspect what lands.

How fast does my app have to respond to a Slack event?

Three seconds, per Slack's docs. Miss it and the delivery counts as failed, and Slack retries nearly immediately, after one minute, and after five. With webhook.co in front, the acknowledgement comes from the ingest endpoint rather than from your laptop over a tunnel.

Point a webhook at it. Watch it land.

Start free: a permanent URL, full inspection, one-command replay — and outbound delivery, because every feature is on every plan. Move up when you need more events.