WebhookToolkit
Discord

Discord webhook tester

Paste a Discord webhook URL, build a message or a rich embed, and send it straight from your browser. You get the real HTTP status back — a green 200, or the exact error to fix. Unlike a capture-only tool, this actually delivers to your channel, then shows you the response.

Discord webhooks are the highest-volume webhook cluster on the web — the one hobbyists reach for first and the one CI/monitoring pipelines fan out to. This page covers both directions: sending a test here, and capturing what another service (GitHub, UptimeRobot, a cron) sends into Discord.

Send a test message or embed

The message is delivered straight from your browser to Discord (their webhook endpoint allows cross-origin POST). The webhook URL is never sent to our servers. We append ?wait=true so Discord returns the created message instead of an empty 204.
fields (max 25)
Embed characters: 97/6000 (Discord rejects the whole message past 6000 total)
JSON payload
{
  "content": "Test message from webhook-toolkit.com ✅",
  "embeds": [
    {
      "title": "Deployment succeeded",
      "description": "Build `#1287` shipped to production in 42s.",
      "color": 5793266,
      "fields": [
        {
          "name": "Environment",
          "value": "production",
          "inline": true
        },
        {
          "name": "Commit",
          "value": "a1b2c3d",
          "inline": true
        }
      ]
    }
  ]
}
curl
curl -X POST "https://discord.com/api/webhooks/ID/TOKEN?wait=true" \
  -H "Content-Type: application/json" \
  -d '{"content":"Test message from webhook-toolkit.com ✅","embeds":[{"title":"Deployment succeeded","description":"Build `#1287` shipped to production in 42s.","color":5793266,"fields":[{"name":"Environment","value":"production","inline":true},{"name":"Commit","value":"a1b2c3d","inline":true}]}]}'
Node / fetch
await fetch("https://discord.com/api/webhooks/ID/TOKEN?wait=true", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
  "content": "Test message from webhook-toolkit.com ✅",
  "embeds": [
    {
      "title": "Deployment succeeded",
      "description": "Build `#1287` shipped to production in 42s.",
      "color": 5793266,
      "fields": [
        {
          "name": "Environment",
          "value": "production",
          "inline": true
        },
        {
          "name": "Commit",
          "value": "a1b2c3d",
          "inline": true
        }
      ]
    }
  ]
}),
});

Anatomy of a Discord webhook URL

Every Discord webhook is fully identified by two values baked into its URL. There is no separate API key and no signature — whoever has the URL can post, which is exactly why you should treat it like a password and regenerate it if it leaks.

Format
https://discord.com/api/webhooks/1234567890123456789/aBcDeF...68-char-token
                                 └────────┬────────┘ └──────────┬──────────┘
                                    webhook id (snowflake)   webhook token
PartWhat it isNotes
webhook id17–20 digit Discord snowflakeEncodes the creation timestamp; wrong id → 404 Unknown Webhook (code 10015)
webhook token~68-char secretWrong/rotated token → 401 Invalid Webhook Token (code 50027)
?wait=trueOptional query flagReturns the created message (200) instead of an empty 204
?thread_id=…Optional query flagPosts into a specific thread of the channel

Where to find it: Server Settings → Integrations → Webhooks → New Webhook, then Copy Webhook URL. You need the Manage Webhooks permission on the target channel. The older discordapp.com host and canary./ptb. subdomains resolve to the same API.

The errors you will actually hit

Discord replies with a numeric HTTP status and a JSON code field. The JSON code is the precise one — two different problems can both surface as a 400.

HTTPcodeMeaningFix
204Success, no body returnedAdd ?wait=true to see the message object
40050035Invalid form body (bad embed)Check field limits: title 256, description 4096, ≤25 fields, ≤6000 total chars
40150027Invalid Webhook TokenToken in the URL is wrong or regenerated — copy a fresh URL
40410015Unknown WebhookThe webhook was deleted or the id is wrong — recreate it
429Rate limitedRead retry_after (seconds) from the body and back off before retrying

Hard limits (they reject, they don't truncate)

These are enforced by Discord — go over and the whole message is rejected with a 400, nothing is silently cut. The 6000-character total is the one that bites: it sums every text field across all embeds in a single message.

FieldLimit
content (plain text)2000 characters
embeds per message10
all embeds combined6000 characters total
embed.title256 characters
embed.description4096 characters
fields per embed25
field.name / field.value256 / 1024 characters
footer.text2048 characters
rate limit~30 requests / 60s per webhook

Copy-paste from your own code

The tool above already emits curl and Node for your exact payload. Here are the canonical forms to keep in a script — note the decimal color and ?wait=true.

curl
curl -X POST "https://discord.com/api/webhooks/ID/TOKEN?wait=true" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Deploy finished",
    "username": "CI",
    "embeds": [{
      "title": "Build #1287",
      "description": "Shipped to production in 42s",
      "color": 5793266,
      "fields": [
        { "name": "env", "value": "production", "inline": true },
        { "name": "commit", "value": "a1b2c3d", "inline": true }
      ]
    }]
  }'
Node (fetch, built into Node 18+)
const res = await fetch(process.env.DISCORD_WEBHOOK + "?wait=true", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    content: "Deploy finished",
    embeds: [{ title: "Build #1287", color: 0x5865f2 }], // hex literal → int
  }),
});
if (res.status === 429) {
  const { retry_after } = await res.json();
  await new Promise((r) => setTimeout(r, retry_after * 1000));
}

Capture what flows INTO Discord

Sending is only half the loop. When you wire GitHub → Discord, an alerting service, or a cron to a Discord webhook and the message never shows up, you need to see the exact bytes and headers the source is producing. Point that source at a Receiver URL first, inspect the raw request, then swap in the real Discord URL once it looks right.

Capture with the ReceiverGitHub webhook testerSlack webhook tester

Questions fréquentes

Where do I get a Discord webhook URL?

Open Server Settings → Integrations → Webhooks → New Webhook (or pick an existing one) → Copy Webhook URL. You need the Manage Webhooks permission on the channel. The URL looks like https://discord.com/api/webhooks/<id>/<token> where the id is a 17–20 digit snowflake and the token is roughly 68 characters.

Is my webhook URL sent to your server?

No. The test message is POSTed directly from your browser to Discord's API — their webhook endpoint returns permissive CORS headers, so no proxy is needed. The URL never leaves your machine except to reach discord.com.

Why did I get a 204 No Content instead of the message body?

A webhook execution returns 204 with an empty body by default. Append ?wait=true to the URL and Discord returns 200 plus the full created message object (id, timestamp, channel_id). This tool adds ?wait=true automatically.

What does 401 code 50027 mean?

"Invalid Webhook Token" — the token part of the URL is wrong or was regenerated. A 404 code 10015 "Unknown Webhook" means the webhook was deleted (or the id is wrong). Both are permanent: no retry will fix them, you need a fresh URL.

Why is embed.color a number and not #5865F2?

Discord expects color as a decimal integer, not a hex string. #5865F2 (Discord blurple) is 5793266 in decimal. This tool converts it for you; if you build the payload by hand, run parseInt('5865F2', 16).

What are the rate limits?

Each webhook is limited to roughly 30 requests per 60 seconds. Exceeding it returns HTTP 429 with a JSON body containing retry_after (seconds to wait) and the X-RateLimit-Reset-After header. Respect retry_after before sending again — hammering it can get the webhook temporarily blocked.

Discord Webhook Tester — send a test message & debug the response · Webhook Toolkit