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

Catch Discord webhook events locally

Discord has two things called webhooks, pointing in opposite directions. This page is about the one that sends events to you — and about getting past the verification gate that guards it.

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.

wbhkdiscord
$ wbhk endpoints create discord-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 Discord

Two unrelated things share the name. The webhook URL an outside service posts to in order to push into Discord is incoming — nothing from Discord ever arrives at your app on it. What you test here is the opposite direction: Webhook Events, which Discord sends to your app. And the URL will not register at all until your handler already clears both halves of Discord's verification gate — the PING acknowledgement and the two signature headers. Verification is the first thing you debug, not the last.

Where the URL goes

The Webhooks page in your app's settings in the Discord Developer Portal is where this lives — left-hand sidebar. Drop the ingest URL into the Endpoint field, flip the Events toggle on, select the events you want your app to receive, and click Save Changes. Nothing flows until that URL is successfully verified. There's an API path too, if you'd rather not click: the docs point you at Edit Current Application.

There's no test button, no resend, no replay control anywhere in the documented flow. The one delivery you can summon is the PING that lands when you add or save the Webhook Events URL — which doubles as your handshake test. Everything else needs the real action behind it: authorize your app somewhere to produce APPLICATION_AUTHORIZED, or drive the real state change behind an ENTITLEMENT_CREATE.

What Discord sends

Names are SCREAMING_SNAKE_CASE, but don't match on the top-level type field — that's a number, 0 for a PING and 1 for everything else. The name you actually care about sits one level down, in event.type, next to a timestamp and, when there is one, the payload.

  • APPLICATION_AUTHORIZED
  • APPLICATION_DEAUTHORIZED
  • ENTITLEMENT_CREATE
  • ENTITLEMENT_UPDATE
  • LOBBY_MESSAGE_CREATE
  • GAME_DIRECT_MESSAGE_CREATE

Worth knowing first

Three seconds, then backoff

Discord expects a 204 with an empty body within three seconds. Miss the window and it retries several times using exponential backoff for up to ten minutes. Fail too often and it stops sending webhook events altogether and tells you by email. Worth knowing before you put a breakpoint in the handler.

Discord probes you with bad signatures

Signature validation isn't advisory. Every request carries X-Signature-Ed25519 and X-Signature-Timestamp, you're expected to check both and answer 401 when they don't hold, and Discord runs routine automated checks that deliberately send invalid signatures. Fail one and it removes your Webhook Events URL, then notifies you by email and System DM.

Ordering is explicitly disclaimed

The very first line of the docs says webhook events, unlike Gateway events, arrive when they arrive and in whatever order they arrive. Reconstruct sequence from the timestamp on the event body rather than from arrival order, and avoid state machines that assume a CREATE lands before its matching UPDATE.

You may not need this at all

The docs put this plainly — if your app is using Gateway events, you don't need to configure a Webhook Events URL. Worth settling before you spend an afternoon on Ed25519 validation for an endpoint you were never going to need.

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

Discord webhooks: common questions

Is a Discord webhook events URL the same as an incoming webhook?

No. An incoming webhook is a URL an external service posts to, so the traffic runs into Discord. A webhook events URL is the outgoing direction: Discord posts to your app when something happens in Discord. Only the second one delivers events you can inspect.

Why won't Discord verify my webhook events URL?

Discord validates the URL only if your endpoint does two things first: acknowledges the PING it sends with a 204 and an empty body, including a valid Content-Type, and validates the two signature headers on every request. If either is missing, the URL is not validated.

Can I resend a Discord webhook event for testing?

Discord documents no resend, redeliver, or replay control for webhook events. Real events require the underlying action, so capture one once and replay it locally instead.

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.