A Discord webhook is a secret URL tied to one channel. POST a JSON body with content (up to 2000 characters), embeds (up to 10), or both, and the message appears in that channel under the webhook's name. No bot or login is needed, which is also why anyone holding the URL can post.
| Field | Type | Notes |
|---|---|---|
| content | string | Message text, up to 2000 characters |
| username | string | Overrides the webhook's name for this message |
| avatar_url | string | Overrides the webhook's avatar for this message |
| embeds | array | Up to 10 rich embed objects |
| allowed_mentions | object | Limits which @mentions actually ping |
| thread_id (query) | snowflake | Posts into a thread in the channel |
| wait (query) | boolean | true returns the created message instead of 204 |
Updated
Webhooks are the quickest way to push alerts, form submissions or deploy notices into a Discord channel. The builder below writes the JSON for you, counts characters against Discord's limits as you type, and turns the result into curl, JavaScript and Python you can paste into a script or server. It does not send anything itself, so your webhook URL never leaves your machine.
Type your message and embed, watch the character counts, and copy the JSON or code. Nothing is sent from this page.
The URL is read from an environment variable so it never lands in your shell history or a commit.
curl -X POST "$DISCORD_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"content": "Deploy finished: v2.4.1 is live", "username": "Deploy bot"}'Uses the built-in fetch in Node 18 and later. wait=true makes Discord return the message so you can log its id.
const res = await fetch(process.env.DISCORD_WEBHOOK_URL + "?wait=true", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: "Shop alerts",
allowed_mentions: { parse: [] },
embeds: [{
title: "New order #1042",
url: "https://example.com/admin/orders/1042",
color: 5216507,
fields: [
{ name: "Total", value: "$84.00", inline: true },
{ name: "Items", value: "3", inline: true },
],
footer: { text: "example.com" },
timestamp: new Date().toISOString(),
}],
}),
});
if (!res.ok) throw new Error("Discord said " + res.status);
console.log((await res.json()).id);json= sets the Content-Type header for you. A 204 status means the message was posted.
import os, requests
r = requests.post(os.environ["DISCORD_WEBHOOK_URL"], json={
"content": "Nightly backup completed",
"allowed_mentions": {"parse": []},
})
r.raise_for_status()
A webhook URL ends in two parts: the webhook id and its token. The token is the only credential, which is why Discord's docs note that executing a webhook needs no other authentication. Anyone with the full URL has the same power you do.
Plain content suits short alerts and supports Discord's markdown. Embeds give you a coloured sidebar, a title link, fields laid out in columns and a footer, which reads better for structured data such as an order or an error report.
You can send both in one call. The content appears above the embeds, and allowed_mentions decides whether any names in it actually notify people.
When you send too fast, Discord answers with a 429 status and a JSON retry_after value in seconds. Respect it and queue messages, rather than retrying in a tight loop. Combining several events into one message with multiple embeds also cuts the number of calls.
You need the Manage Webhooks permission on the server or channel. In your Discord server's settings, create a webhook for the channel and copy its URL.
Usually the body is empty or invalid. You must send at least one of content, embeds, components, a file or a poll, and content must be 2000 characters or fewer. Also send the header Content-Type: application/json, otherwise the body is not read as JSON.
Do not. Any page that does so exposes the URL to every visitor, who can then post anything to your channel. Send from a server, a serverless function or a script, and have your page call that instead.
Discord documents a title of up to 256 characters, field values up to 1024 characters, and a combined total of 6000 characters across title, description, field names and values, footer text and author name in all embeds of one message.
No. A webhook can only post (and edit or delete its own messages). Reading channels, reacting to commands or replying to people needs a bot application.
Related: Webhook vs API, Stripe webhooks guide, JSON formatter, HTTP status codes.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.