Guide/Developers/Outgoing webhooks: receiving and verifying
Outgoing webhooks: receiving and verifying — Discord Bot…
How to receive signed security events (raids, nukes, escalations) in your own service and verify the signature.
Quick answer
Check an endpoint
Dashboard → Security → Webhooks → Test # signed sample event; the row shows status, latency and the last 20 deliveriesAsk the guide
Step by step
!security webhook add https://hooks.example.com/sweet raid.detected,nuke.detected,antinuke.faststrike
!security webhook add https://hooks.example.com/all *
!security webhook list · !security webhook remove <id>Dashboard: Security → Webhooks. The secret is shown once, at creation. URLs must be https and resolve to a public address — checked when added and again before every delivery, so a hostname re-pointed at a private network stops receiving events. Redirects are not followed. After 25 consecutive failures the hook is disabled.
Events
nuke.detected, nuke.emergency, antinuke.faststrike, antinuke.damageReport, antinuke.suspicious, antinuke.selfAttack, raid.detected, spam.bot, escalation.changed, lockdown.started, lockdown.ended, channel.nuked, or * for all.
Request
POST /your/path
content-type: application/json
x-sweet-event: nuke.detected
x-sweet-signature: t=1758540000000,v1=<hex hmac-sha256>
{ "event": "nuke.detected", "guildId": "…", "timestamp": "2026-09-22T08:10:02.000Z", "data": { "severity": "critical", "title": "…", "description": "…", "actorId": "…", … } }Verify (Node)
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(secret, header, rawBody, toleranceSec = 300) {
const m = /t=(\d+),v1=([a-f0-9]{64})/.exec(header ?? '');
if (!m) return false;
const [, t, sig] = m;
if (Math.abs(Date.now() - Number(t)) > toleranceSec * 1000) return false; // replay window
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return expected.length === sig.length && timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}Sign over the raw body bytes exactly as received, not a re-serialised object. Respond with any 2xx quickly; do the work afterwards.
Copy and try
Check an endpoint
Dashboard → Security → Webhooks → Test # signed sample event; the row shows status, latency and the last 20 deliveriesGood to know
- Payloads carry ids, counts and short reasons only; message content, evidence and long text are stripped before signing.
- Sign over the raw body bytes; re-serialising breaks the signature.
- Respond 2xx fast; 25 consecutive failures disable the hook.
Still stuck? Ask in the support server.