Live
Black Hat USADark ReadingBlack Hat AsiaAI Business5 best practices to secure AI systemsAI NewsAI models fail at robot control without human-designed building blocks but agentic scaffolding closes the gap - the-decoder.comGoogle News - AI roboticsVulkan backend much easier on the CPU and GPU memory than CUDA.Reddit r/LocalLLaMAAn interview with Mustafa Suleyman on Microsoft s AI reorg, how revising its OpenAI contract "unlocked [Microsoft s] ability to pursue superintelligence", more (Hayden Field/The Verge)TechmemeTikTok's 'hidden game' shows it wants even more of our timeCreative Bloq AI DesignUS crude tops US$110, Wall Street falls after Trump vows more Iran attacksSCMP Tech (Asia AI)Qwen3.6-Plus: Towards Real World AgentsHacker News TopUnlocking the promise of smart factories: Advanced analytics powered by 5G provides a road map to the futureTech Monitor1.13.0a7CrewAI ReleasesCalls to Regulate Smart Glasses Are Officially DeafeningGizmodoUMW Inaugural AI Expert-in-Residence Shares Insight on Technology’s ‘Tremendous’ Impact - University of Mary WashingtonGoogle News: AIAmazon vs. Apple: Which Is the Better Artificial Intelligence (AI) Stock to Buy Today? - The Motley FoolGoogle News: AIBlack Hat USADark ReadingBlack Hat AsiaAI Business5 best practices to secure AI systemsAI NewsAI models fail at robot control without human-designed building blocks but agentic scaffolding closes the gap - the-decoder.comGoogle News - AI roboticsVulkan backend much easier on the CPU and GPU memory than CUDA.Reddit r/LocalLLaMAAn interview with Mustafa Suleyman on Microsoft s AI reorg, how revising its OpenAI contract "unlocked [Microsoft s] ability to pursue superintelligence", more (Hayden Field/The Verge)TechmemeTikTok's 'hidden game' shows it wants even more of our timeCreative Bloq AI DesignUS crude tops US$110, Wall Street falls after Trump vows more Iran attacksSCMP Tech (Asia AI)Qwen3.6-Plus: Towards Real World AgentsHacker News TopUnlocking the promise of smart factories: Advanced analytics powered by 5G provides a road map to the futureTech Monitor1.13.0a7CrewAI ReleasesCalls to Regulate Smart Glasses Are Officially DeafeningGizmodoUMW Inaugural AI Expert-in-Residence Shares Insight on Technology’s ‘Tremendous’ Impact - University of Mary WashingtonGoogle News: AIAmazon vs. Apple: Which Is the Better Artificial Intelligence (AI) Stock to Buy Today? - The Motley FoolGoogle News: AI
AI NEWS HUBbyEIGENVECTOREigenvector

How to Test Discord Webhooks with HookCap

DEV Communityby Henry HangApril 2, 202611 min read0 views
Source Quiz

<h1> How to Test Discord Webhooks with HookCap </h1> <p>Discord has two distinct webhook concepts that are easy to confuse. Understanding which one you are dealing with determines how you test it.</p> <p><strong>Incoming webhooks</strong> — You POST to a Discord-provided URL to send messages to a channel. Discord is the receiver. You do not need to expose a server.</p> <p><strong>Bot event webhooks / Interactions endpoints</strong> — Discord POSTs to a URL you provide when events happen (slash commands, button clicks, message events). Your server is the receiver.</p> <p>This guide focuses on the second type: webhooks where Discord sends events <em>to</em> your server. That is the kind that requires a public HTTPS URL and that HookCap helps you test.</p> <h2> Discord Interactions Endpoint <

How to Test Discord Webhooks with HookCap

Discord has two distinct webhook concepts that are easy to confuse. Understanding which one you are dealing with determines how you test it.

Incoming webhooks — You POST to a Discord-provided URL to send messages to a channel. Discord is the receiver. You do not need to expose a server.

Bot event webhooks / Interactions endpoints — Discord POSTs to a URL you provide when events happen (slash commands, button clicks, message events). Your server is the receiver.

This guide focuses on the second type: webhooks where Discord sends events to your server. That is the kind that requires a public HTTPS URL and that HookCap helps you test.

Discord Interactions Endpoint

If you are building a Discord app with slash commands, buttons, select menus, or modals, Discord will POST to an Interactions Endpoint URL you register in the Discord Developer Portal. You need to handle these requests on your server.

Discord also uses Gateway (WebSocket) for most bot events. But slash commands and components use the HTTP Interactions endpoint, which is what we will test here.

Step 1: Create a HookCap Endpoint

Go to hookcap.dev, sign up, and create an endpoint. You get a URL like:

https://hookcap.dev/e/your-endpoint-id

Enter fullscreen mode

Exit fullscreen mode

Step 2: Register the Endpoint in Discord

Go to the Discord Developer Portal:

  • Select your application

  • Under General Information, find the Interactions Endpoint URL field

  • Paste your HookCap URL

  • Click Save Changes

Discord will immediately send a verification ping to the URL to confirm it responds correctly. More on this below.

Step 3: Understand the Verification Ping

When you save an Interactions Endpoint URL, Discord sends a PING interaction and expects a PONG response. This is how Discord confirms your endpoint is alive.

Your handler (or HookCap in passthrough mode) must respond to this before Discord accepts the URL.

The ping looks like:

{  "id": "123456789",  "type": 1,  "token": "interaction_token" }

Enter fullscreen mode

Exit fullscreen mode

Your server must respond with:

{  "type": 1 }

Enter fullscreen mode

Exit fullscreen mode

For HookCap's purpose (capturing and inspecting), you can temporarily use Auto-Forward to route the verification ping to your local server so it can respond correctly, then inspect subsequent interactions.

Step 4: Inspect Real Interactions

Once your app is registered, trigger interactions in Discord:

  • Run a slash command

  • Click a button in a Discord message your bot sent

  • Select an option from a select menu

HookCap captures each Discord POST in real time. A typical slash command interaction looks like:

{  "id": "987654321098765432",  "type": 2,  "data": {  "id": "123456789012345678",  "name": "ping",  "type": 1,  "options": []  },  "guild_id": "111111111111111111",  "channel_id": "222222222222222222",  "member": {  "user": {  "id": "333333333333333333",  "username": "testuser",  "discriminator": "0001"  },  "roles": []  },  "token": "AbCdEfGhIjKlMnOpQrStUvWxYz...",  "version": 1 }

Enter fullscreen mode

Exit fullscreen mode

You can inspect:

  • type — 1 = PING, 2 = APPLICATION_COMMAND, 3 = MESSAGE_COMPONENT, 4 = APPLICATION_COMMAND_AUTOCOMPLETE, 5 = MODAL_SUBMIT

  • data.name — the slash command name

  • data.options — arguments passed to the command

  • member.user — who triggered it

  • token — used to respond to the interaction (time-limited)

Verifying Discord Signatures

Discord signs each request with your application's public key using Ed25519. This is different from the HMAC-SHA256 most providers use.

The headers Discord sends:

X-Signature-Ed25519:  X-Signature-Timestamp: 

Enter fullscreen mode

Exit fullscreen mode

Discord signs: timestamp + body (as bytes).

const nacl = require('tweetnacl');

function verifyDiscordSignature(publicKey, signature, timestamp, body) { const message = Buffer.concat([ Buffer.from(timestamp, 'utf-8'), Buffer.from(body), ]);

return nacl.sign.detached.verify( message, Buffer.from(signature, 'hex'), Buffer.from(publicKey, 'hex') ); }

app.post('/interactions', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-signature-ed25519']; const timestamp = req.headers['x-signature-timestamp']; const publicKey = process.env.DISCORD_PUBLIC_KEY; // from Developer Portal

if (!verifyDiscordSignature(publicKey, signature, timestamp, req.body)) { return res.status(401).send('Invalid signature'); }

const interaction = JSON.parse(req.body);

// Handle PING verification if (interaction.type === 1) { return res.json({ type: 1 }); }

// Handle slash commands if (interaction.type === 2) { const command = interaction.data.name;

if (command === 'ping') { return res.json({ type: 4, // CHANNEL_MESSAGE_WITH_SOURCE data: { content: 'Pong! 🏓', }, }); } }

// Unknown interaction type res.status(400).json({ error: 'Unknown interaction type' }); });`

Enter fullscreen mode

Exit fullscreen mode

You can get your public key from the Discord Developer Portal under General Information → Public Key.

Using HookCap Auto-Forward for Local Testing

The challenge with Discord interactions is the time limit on interaction tokens. You have 3 seconds to respond to an interaction, otherwise Discord shows a "This interaction failed" message to the user.

HookCap Auto-Forward (Pro) solves this cleanly:

  • Enable Auto-Forward on your HookCap endpoint

  • Set the forward URL to http://localhost:3000/interactions

  • Register your HookCap URL in the Discord Developer Portal

  • Discord sends interactions → HookCap captures + forwards to your local server → response goes back

Because HookCap proxies the request and response in real time, your 3-second response window is preserved. HookCap also stores the full interaction for inspection even after it has been responded to.

Discord → HookCap endpoint → (captured) → Auto-Forward → localhost:3000  ↓ Discord ← HookCap endpoint ← (forwarded response) ←───────────┘

Enter fullscreen mode

Exit fullscreen mode

Testing Without Live Discord (Replay)

Once you have captured a real Discord interaction in HookCap, you can replay it to your local server without going through Discord again.

This is useful for:

  • Testing edge cases with specific payload structures

  • Reproducing bugs with exact payloads from production

  • Running your handler through CI without a real Discord bot configured

When replaying, note that the interaction token in the payload has already expired — you cannot respond to Discord with it. But you can still test your handler's routing, parsing, and internal logic.

Discord Outgoing Webhooks (Sending to Channels)

If you want to test the other direction — your app sending messages to a Discord channel via a Discord webhook URL — you do not need HookCap for the testing itself. But you can use HookCap as a mock Discord endpoint to confirm your app is sending the correct payloads.

Set your webhook URL to a HookCap endpoint instead of a real Discord webhook URL. Your app will POST to HookCap, and you can inspect exactly what would have been sent to Discord.

const fetch = require('node-fetch');

// Instead of real Discord webhook URL, use HookCap for testing const WEBHOOK_URL = process.env.NODE_ENV === 'test' ? 'https://hookcap.dev/e/your-test-endpoint' : process.env.DISCORD_WEBHOOK_URL;

await fetch(WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: 'Hello from my app!', embeds: [{ title: 'New Order', description: 'Order #1234 has been placed', color: 0x57F287, fields: [ { name: 'Customer', value: 'John Doe', inline: true }, { name: 'Amount', value: '$99.00', inline: true }, ], }], }), });`

Enter fullscreen mode

Exit fullscreen mode

Inspect the HookCap capture to verify your embed structure, color values, and field layout are correct before sending to real Discord channels.

Common Issues

Endpoint Verification Fails

Discord rejects your Interactions Endpoint URL if the ping fails. Make sure:

  • Your server is reachable at the URL you provided

  • It responds to type: 1 with { type: 1 }

  • Signature verification is correct (Discord verifies its own ping signature)

Using HookCap's Auto-Forward, you can route the ping to your local server so it handles verification while HookCap captures the interaction.

Interaction Token Expired

If you replay a captured interaction and your handler tries to call Discord's API with the old token, the API will return a 401. Use replay for testing handler logic only — do not attempt to respond to Discord with replayed tokens.

Ed25519 Library Missing

Discord requires Ed25519 signature verification. Node.js does not have this built in. Use tweetnacl:

npm install tweetnacl

Enter fullscreen mode

Exit fullscreen mode

Or use the discord-interactions package which wraps this:

npm install discord-interactions

Enter fullscreen mode

Exit fullscreen mode

const { verifyKeyMiddleware } = require('discord-interactions');

app.post('/interactions', verifyKeyMiddleware(process.env.DISCORD_PUBLIC_KEY), (req, res) => { // Signature already verified by middleware const interaction = req.body; // ... } );`

Enter fullscreen mode

Exit fullscreen mode

Summary

Testing Discord webhooks with HookCap:

  • Interactions Endpoint — Register your HookCap URL in the Discord Developer Portal; Discord will send slash command and component interactions to it

  • Signature verification — Discord uses Ed25519 (not HMAC-SHA256); use tweetnacl or discord-interactions

  • Auto-Forward — Forward live interactions to your local server with the 3-second response window intact

  • Outgoing webhooks — Use HookCap as a mock Discord endpoint to verify payload structure before sending to real channels

  • Replay — Use captured interactions to test handler logic without re-triggering events in Discord

Was this article helpful?

Sign in to highlight and annotate this article

AI
Ask AI about this article
Powered by Eigenvector · full article context loaded
Ready

Conversation starters

Ask anything about this article…

Daily AI Digest

Get the top 5 AI stories delivered to your inbox every morning.

More about

versionproductapplication

Knowledge Map

Knowledge Map
TopicsEntitiesSource
How to Test…versionproductapplicationcomponentDEV Communi…

Connected Articles — Knowledge Graph

This article is connected to other articles through shared AI topics and tags.

Knowledge Graph100 articles · 150 connections
Scroll to zoom · drag to pan · click to open

Discussion

Sign in to join the discussion

No comments yet — be the first to share your thoughts!

More in Products