How the webhook URL works. It is a public address that records whatever is sent to it and
answers 200. An inbox keeps the 50 most recent requests, accepts bodies up to 256 KB, and is
deleted 24 hours after it was created — or sooner if you press Delete URL or our server
restarts, because requests are held in memory and never written to disk.
Anyone who has the URL can read what it received. Use sandbox and test-mode accounts, do not route production traffic or customer data through it, and delete it when you are done. Privacy details.
What is a Discord webhook?
A Discord webhook is a URL attached to a channel. Send it an HTTP POST with a small JSON body and the message appears in that channel — no bot user, no gateway connection, no OAuth. It is the standard way to push build results, alerts and form submissions into a server.
The URL has the form https://discord.com/api/webhooks/{webhook.id}/{webhook.token}. The token in the path is the only authentication, which makes the URL itself the secret.
The request you send to Discord
The method, the URL shape and a body that uses the most common fields.
POST /api/webhooks/123456789012345678/WEBHOOK-TOKEN-PLACEHOLDER HTTP/1.1
Host: discord.com
Content-Type: application/json
User-Agent: your-app/1.0
{
"username": "Deploy Bot",
"content": "Build **#482** finished.",
"embeds": [
{
"title": "api-service deployed to production",
"url": "https://example.com/builds/482",
"description": "All 318 tests passed.",
"color": 3066993,
"fields": [
{
"name": "Branch",
"value": "main",
"inline": true
},
{
"name": "Duration",
"value": "2m 14s",
"inline": true
}
],
"timestamp": "2026-01-01T12:00:00.000Z"
}
],
"allowed_mentions": {
"parse": []
}
}
At least one of content, embeds or a file is required. color is a decimal integer, not a hex string. username and avatar_url override the webhook's defaults for this one message. allowed_mentions with an empty parse list stops text such as @everyone inside user-supplied content from pinging the server — set it whenever the message contains input you did not write.
Headers you send
Unlike the other examples in this section, these are headers you set on your own request.
| Header | Example | What it is |
|---|---|---|
Content-Type | application/json | Required for a JSON body. File uploads use multipart/form-data with the JSON in a payload_json part. |
User-Agent | your-app/1.0 | Optional, but a descriptive value helps if Discord ever needs to identify a misbehaving client. |
Header names are case-insensitive. Your framework may show them lower-cased, and HTTP/2 always does.
Authentication: the URL is the credential
There is nothing to sign and no header to add. Whoever holds the webhook URL can post to the channel as that webhook, so treat it exactly like a password: keep it in a secret store, never in client-side code or a public repository, and delete and recreate the webhook if it leaks. Automated scanners look for these URLs.
That also means a browser cannot safely call it — any page that does has just published its own credential. Send from a server, or from a tool where the URL stays with you.
// Node 18+. WEBHOOK_URL comes from your environment, never from source control.
const res = await fetch(process.env.WEBHOOK_URL + '?wait=true', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: 'Build **#482** finished.',
allowed_mentions: { parse: [] },
}),
});
if (res.status === 429) {
const body = await res.json();
// retry_after is in seconds and may be fractional
await new Promise((r) => setTimeout(r, body.retry_after * 1000));
}
Responses and rate limits
A successful execute returns 204 No Content with an empty body. Append ?wait=true and Discord instead returns 200 with the created message object, which you need if you intend to edit or delete that message later. A malformed body returns 400 with a JSON error describing the offending field, and a deleted webhook returns 404.
Webhooks are rate limited. When you exceed the limit Discord returns 429 with a JSON body containing retry_after, and every response carries X-RateLimit-* headers describing the current bucket. Read those values rather than hard-coding a delay; a client that keeps posting into a 429 can get its address temporarily blocked.
Check your payload before it reaches a channel
- Press Create webhook URL at the top of this page.
- Point your script, CI job or alerting tool at that address instead of the Discord URL and let it fire.
- Read the request in the inbox above: is the body JSON, is
Content-Typeset, did the template variables expand? - Once it looks right, swap in the real Discord webhook URL.
To create the Discord side: in the server, open the channel's settings, choose Integrations → Webhooks → New Webhook, and copy its URL. To send a request to Discord from the browser, the Discord API tester has the console pre-filled.
To run a caught request against your own code, select it and press Open in API Tester: the method, headers and body are loaded into the request console, where you enter your server's public URL and send it. A body you edit will no longer match its signature — that is the signature doing its job.
Things that catch people out
- Slack-format and GitHub-format payloads need a suffix. Appending
/slackor/githubto the URL makes Discord accept those providers' formats; the plain URL expects Discord's own JSON. - Limits are per field.
contenthas a character cap, and embeds have caps per title, description, field and in total. An over-long value is rejected with400, not truncated. - This is not the Interactions endpoint. Slash commands and buttons are delivered to your server by Discord and are signed with Ed25519 — a separate mechanism from channel webhooks.
api-tester.com is independent and is not affiliated with Discord. Providers change header names, limits and retry schedules; treat the official Discord documentation as the source of truth.
Related examples and tools
Twilio Webhook Example
Twilio's webhooks are form posts, not JSON, and the signature covers your URL as well as the parameters.
GitLab Webhook Example
The JSON a GitLab project webhook posts on a push, the headers that describe it, and the secret token that is compared rather than computed.
Telegram Webhook Example
The Update object Telegram posts to a bot's webhook, the optional secret-token header, and the trick of answering with an API call in the response body.
SendGrid Webhook Example
SendGrid's Event Webhook posts a batch — a JSON array of email events — and signs it with ECDSA rather than an HMAC.
WooCommerce Webhook Example
What a WooCommerce store posts when an order, product or customer changes — the X-WC-Webhook-* headers, the REST-shaped JSON, and the rule that switches a failing webhook off.
Discord API Tester
Send requests to discord.com/api from the browser, including webhook executes.
Curl POST JSON
Send a JSON body like this one from a terminal.
Webhook Tester
The inbox on its own page, plus a guide to signatures, retries and idempotent handlers.
All Webhook Examples
30 providers side by side: content type, signature scheme and retry behaviour.
Other webhooks with no signature
References
- Official Discord documentation — The provider's own guide to the requests described on this page.
- Discord Developer Docs: rate limits — The rate-limit headers and how to handle a 429.
- Discord Developer Docs: message resource — The message fields, including embeds, that a webhook body can carry.
These links leave api-tester.com, which is independent of the companies and projects they point to.
Discord webhook FAQ
How do I send a message with a Discord webhook?
Send an HTTP POST to the webhook URL with Content-Type: application/json and a body containing content, embeds or both. A successful request returns 204 No Content.
What JSON does a Discord webhook accept?
A message object: content for text, embeds for rich cards, plus optional username, avatar_url, tts, allowed_mentions and thread parameters. At least one of content, embeds or a file is required.
Why does my Discord webhook return 204 with no body?
That is the success response. Add ?wait=true to the URL to receive a 200 with the created message object instead.
Is a Discord webhook URL a secret?
Yes. The token in the URL is the only authentication, so anyone with the URL can post to the channel. Store it as a secret and recreate the webhook if it is exposed.
What does a 429 from a Discord webhook mean?
You hit a rate limit. The JSON response contains retry_after, the number of seconds to wait before sending again.