Provider reference / Discord

How Discord delivers webhooks

Interactions want an initial response within 3 seconds, signed with Ed25519 instead of an HMAC. The verified format and a Web Crypto verifier.

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 budget3s

Interaction endpoints must send an initial response within 3 seconds

Retrynot published by the vendor
Gives upnot published by the vendor
Sourcehttps://docs.discord.com/developers/interactions/receiving-and-responding

Signature

Verified against a working verifier proven by a test suite, not read from documentation. Last verified 2026-08-20.

AlgorithmEd25519
Signed payload{timestamp}{body}
Encodinghex
Headerx-signature-ed25519 + x-signature-timestamp
Tolerancenone enforced

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.

// Ed25519, not HMAC: verify with the application's public key (hex).
const hex = (s) => Uint8Array.from(s.match(/../g), (b) => parseInt(b, 16));

const key = await crypto.subtle.importKey(
  "raw",
  hex(publicKey), // Developer Portal → Application → Public Key
  { name: "Ed25519" },
  false,
  ["verify"],
);
const valid = await crypto.subtle.verify(
  "Ed25519",
  key,
  hex(req.headers["x-signature-ed25519"]),
  new TextEncoder().encode(req.headers["x-signature-timestamp"] + rawBody),
);

Discord actively probes endpoints with invalid signatures and rejects the URL if they pass, so a stubbed-out verifier fails onboarding, not just security review.

What bites

The 3-second budget applies to the initial interaction response. The escape hatch is type 5 (deferred): acknowledge inside the window, then follow up when the real work finishes.

Read more

AnyHook sits in front of endpoints that receive from Discord: 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.

How it works →