Delivery behaviour
Read from the vendor's own documentation, last checked 2026-08-06. Where the vendor states no number, this table carries none.
| Response budget | 3s |
|---|---|
| Retry | 3 retries: immediately, after 1 min, after 5 min |
| Gives up | Event subscriptions disabled if over 95% of attempts fail within 60 min |
| Source | https://docs.slack.dev/apis/events-api/ |
Signature
Verified against a working verifier proven by a test suite, not read from documentation. Last verified 2026-08-20.
| Algorithm | HMAC-SHA256 |
|---|---|
| Signed payload | v0:{timestamp}:{body} |
| Encoding | hex |
| Header | x-slack-signature = v0=hex |
| Tolerance | 5 min |
Verify it
The raw request body, byte for byte, before any JSON parsing. Every scheme on this page breaks the moment a framework re-serializes the payload.
const crypto = require("node:crypto");
const ts = req.headers["x-slack-request-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) throw new Error("stale");
const expected =
"v0=" +
crypto
.createHmac("sha256", signingSecret) // Slack App → Basic Information
.update(`v0:${ts}:${rawBody}`)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(req.headers["x-slack-signature"]),
Buffer.from(expected),
);What bites
Three seconds is the tightest budget of any major sender, and the three retries land within five minutes — a handler that is slow rather than down fails all four attempts inside one incident.
The disable rule is a rate, not a count: over 95% of attempts failing within 60 minutes turns event subscriptions off for the whole app, and your users watch the bot go quiet in the channel while it happens.
Read more
AnyHook sits in front of endpoints that receive from Slack: it answers inside the budget above, retries on its own schedule when your server is down, and keeps every event replayable. Change one URL, keep your code.