Discord

Receive Discord interactions and webhook events, verified with Ed25519.

Discord signs with Ed25519, so the provider takes the application's public key (from the developer portal's General Information page), not a shared secret. Verification runs on Web Crypto, with replay protection on the signed timestamp.

Discord also validates your endpoint with PING requests that expect a specific answer, so return it from the handler:

app/api/webhooks/discord/route.ts
import { webhook, discord } from "next-webhooks";

export const POST = webhook({
  provider: discord({ publicKey: process.env.DISCORD_PUBLIC_KEY! }),
  handler: async (event) => {
    const payload = event.payload as { type?: number };
    if (payload?.type === 1) {
      // Interactions PING
      return Response.json({ type: 1 });
    }
    if (payload?.type === 0) {
      // Webhook events PING
      return new Response(null, { status: 204 });
    }
    if (event.type === "APPLICATION_AUTHORIZED") {
      // ...
    }
  },
});

Notes

  • event.type is the webhook event name (APPLICATION_AUTHORIZED and friends); interaction payloads use numeric types, so read event.payload.type for those
  • publicKey accepts an array during key rotation
  • In tests, generate a key pair with discordKeys() from next-webhooks/testing and sign requests with discordHeaders()