Skip to content

Get a webhook URL

Status Stable · Last verified 2026-07-11 · API v10 · Sources Support: Intro to Webhooks, Webhook resource

This is the headline task: obtain a DISCORD_WEBHOOK_URL so you can post to a channel. Two ways — the UI (recommended, 60 seconds) and the API (for automation). Then verify it, secure it, and know how to revoke it.

  • A server where you have Manage Webhooks (part of Manage Server). If you don’t, ask a server admin — they can create the webhook and hand you the URL.
  • A target text channel.
Section titled “Method A — Create it in the Discord app (recommended)”
  1. Open your server and hover the target text channel → click the ⚙️ gear (Edit Channel).
    • Or: Server Settings → Integrations → Webhooks.
  2. Choose Integrations → Webhooks → New Webhook (in older layouts: Create Webhook).
  3. Give it a name (this is the default display name) and, optionally, an avatar and a specific channel.
  4. Click Copy Webhook URL.
  5. Click Save Changes.

That copied string is your DISCORD_WEBHOOK_URL. It looks like:

https://discord.com/api/webhooks/1234567890123456789/AbCdEf-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
└──── webhook id ───┘ └──────────────── webhook token (secret) ─────────────────┘
  • The id is public-ish; the token after the last / is the secret that grants posting. Treat the whole URL as a password.

Method B — Create it via the API (for automation)

Section titled “Method B — Create it via the API (for automation)”

Requires a bot/app token with Manage Webhooks in the target channel. This is only worth it if you’re provisioning webhooks programmatically.

Terminal window
# POST /channels/{channel.id}/webhooks
curl -X POST "https://discord.com/api/v10/channels/CHANNEL_ID/webhooks" \
-H "Authorization: Bot $DISCORD_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "atlas-notifier" }'

The JSON response contains id and token; the executable URL is:

https://discord.com/api/v10/webhooks/{id}/{token}

GET /channels/{channel.id}/webhooks lists existing webhooks; DELETE /webhooks/{webhook.id} (with a bot token) or DELETE /webhooks/{webhook.id}/{token} (token-authenticated, no auth header) removes one. See Send messages for executing it.

The fastest check — a one-line POST (no auth header needed; the token is in the URL):

Terminal window
curl -X POST "$DISCORD_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{ "content": "✅ Webhook is live — sent from curl." }'

Expected: HTTP 204 No Content (nothing in the body) and a message in the channel. Prefer to run a real example?

Terminal window
cd examples/webhook-minimal
cp .env.example .env # paste your URL as DISCORD_WEBHOOK_URL
node send.mjs

Put it in an environment file, never in code:

# .env (git-ignored — see .gitignore)
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123.../AbC...
// Node ≥ 20 has global fetch; read the secret from the environment.
const url = process.env.DISCORD_WEBHOOK_URL;
await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content: "Hello from the atlas 👋" }),
});
Symptom Cause Fix
401 Unauthorized / 404 Unknown Webhook URL wrong, or webhook was deleted/regenerated Re-copy the URL; recreate if deleted
400 with content/embeds errors Empty message, or >2000 chars / >10 embeds / >6000 embed chars Trim payload; see limits
429 Too Many Requests Rate limited (~30 msg/min per webhook) Honor retry_after; batch messages
@everyone didn’t ping Blocked by default Set allowed_mentions explicitly (use sparingly)
Message posts but wrong name/avatar Per-message override not set Add username / avatar_url to the payload

If a webhook URL leaks, delete or regenerate it immediately — rotation is the real fix, not scrubbing logs:

  • UI: channel/settings → Integrations → Webhooks → (the webhook) → Delete Webhook. Recreate to get a fresh URL.
  • API: DELETE https://discord.com/api/v10/webhooks/{id}/{token}.

The old URL stops working the instant it’s deleted.

  • Send messages — embeds, files, threads, usernames, allowed_mentions, and rate limits, with copy-paste payloads.