Discord Webhook Setup Guide¶
Guide to create the 4 Discord channels and configure webhooks for the Freeze Design alerting system.
Overview¶
The alerting system uses 4 Discord channels, each with a specific purpose:
| Channel | Purpose | Notification Source |
|---|---|---|
#errors |
Error spikes, new issues, regressions | Sentry Discord integration (bot) |
#payments |
Payment-related errors | Sentry Discord integration (bot) |
#backups |
Daily backup summaries, backup failures | Django code via webhook |
#admin |
Admin audit trail (delete actions) | Django code via webhook |
Two notification mechanisms are used:
- Sentry Discord bot (for
#errorsand#payments): Configured in Sentry UI, routes alerts directly. See the Monitoring Runbook for Sentry alert configuration. - Custom Discord webhooks (for
#backupsand#admin): Configured as env vars, called by Django application code.
All 4 channels need to be created. Webhooks are only needed for #backups and #admin.
Channel Setup¶
Step 1: Create a Category (Optional but Recommended)¶
Organizing alert channels under a category keeps your Discord server tidy.
- Right-click your server name at the top of the channel list
- Select Create Category
- Name it
FREEZE DESIGN ALERTS(or similar) - Click Create Category
Step 2: Create the 4 Channels¶
For each channel in the table below:
- Click the + next to the category name (or next to "Text Channels")
- Select Text Channel
- Enter the channel name
- Click Create Channel
| Channel Name | Description to Set |
|---|---|
errors |
Sentry error alerts - new issues, regressions, error spikes |
payments |
Payment error alerts from Sentry |
backups |
Daily backup summaries and failure alerts |
admin |
Admin audit trail - delete action notifications |
Step 3: Set Channel Permissions (Recommended)¶
To prevent accidental messages in alert channels:
- Click the gear icon next to the channel name (Edit Channel)
- Go to Permissions
- Under
@everyone, deny Send Messages - Add the Sentry bot role and grant Send Messages and Embed Links (for
#errorsand#payments) - For
#backupsand#admin, the webhook will bypass role permissions automatically
Webhook Creation¶
Webhooks are needed for #backups and #admin only. The #errors and #payments channels use Sentry's native Discord bot instead.
Create Webhook for #backups¶
- Right-click the
#backupschannel - Select Edit Channel
- Go to Integrations in the left menu
- Click Webhooks
- Click New Webhook
- Set the name to
Freeze Design Backups(or similar) - Optionally upload an avatar image
- Click Copy Webhook URL
- Save the URL -- you will need it for the environment variable
Create Webhook for #admin¶
- Right-click the
#adminchannel - Select Edit Channel
- Go to Integrations > Webhooks
- Click New Webhook
- Set the name to
Freeze Design Admin - Click Copy Webhook URL
- Save the URL
Environment Variables¶
New Environment Variables¶
Add these to your .env.production file:
# Discord Webhook URLs (custom notifications from Django)
DISCORD_WEBHOOK_BACKUPS=https://discord.com/api/webhooks/YOUR_BACKUPS_WEBHOOK_ID/YOUR_TOKEN
DISCORD_WEBHOOK_ADMIN=https://discord.com/api/webhooks/YOUR_ADMIN_WEBHOOK_ID/YOUR_TOKEN
# Discord Webhook URLs (for future use if Sentry native integration is not available)
DISCORD_WEBHOOK_ERRORS=https://discord.com/api/webhooks/YOUR_ERRORS_WEBHOOK_ID/YOUR_TOKEN
DISCORD_WEBHOOK_PAYMENTS=https://discord.com/api/webhooks/YOUR_PAYMENTS_WEBHOOK_ID/YOUR_TOKEN
Legacy Environment Variable Migration¶
The codebase previously used different env var names. The following mapping applies:
| Old Variable | New Variable | Used By |
|---|---|---|
BACKUP_DISCORD_WEBHOOK |
DISCORD_WEBHOOK_BACKUPS |
backup_notifications.py, backup_database.py |
ADMIN_DISCORD_WEBHOOK |
DISCORD_WEBHOOK_ADMIN |
discord_admin_notifications.py, health_checks.py |
DISK_ALERT_DISCORD_WEBHOOK |
DISCORD_WEBHOOK_ERRORS |
health_checks.py (disk space alerts) |
During migration, set both old and new env vars to avoid breaking existing notifications:
# Keep old vars until code is fully migrated
BACKUP_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
ADMIN_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
# Add new vars (same webhook URLs or new ones for the dedicated channels)
DISCORD_WEBHOOK_BACKUPS=https://discord.com/api/webhooks/...
DISCORD_WEBHOOK_ADMIN=https://discord.com/api/webhooks/...
Once the code migration is complete (all services use the new DISCORD_WEBHOOK_* env vars), you can remove the old variables.
Sentry Discord Bot vs Custom Webhooks¶
| Feature | Sentry Discord Bot | Custom Webhooks |
|---|---|---|
| Setup | Installed via Sentry Integrations | Created per-channel in Discord |
| Trigger | Sentry alert rules fire automatically | Django code calls webhook URL |
| Formatting | Sentry-formatted messages with links | Custom embed payloads from code |
| Channels | #errors, #payments |
#backups, #admin |
| Config location | Sentry UI (alert rule actions) | .env.production (webhook URLs) |
| Failure mode | Sentry retries delivery | Code logs warning, does not retry |
Testing Webhooks¶
Test with curl¶
After creating webhooks, verify they work before deploying:
Test #backups Webhook¶
curl -H "Content-Type: application/json" \
-X POST \
-d '{"embeds": [{"title": "Test: Backup Webhook", "description": "If you see this, the #backups webhook is working.", "color": 3066993}]}' \
"https://discord.com/api/webhooks/YOUR_BACKUPS_WEBHOOK_ID/YOUR_TOKEN"
You should see a green-colored embed message appear in #backups.
Test #admin Webhook¶
curl -H "Content-Type: application/json" \
-X POST \
-d '{"embeds": [{"title": "Test: Admin Webhook", "description": "If you see this, the #admin webhook is working.", "color": 3447003}]}' \
"https://discord.com/api/webhooks/YOUR_ADMIN_WEBHOOK_ID/YOUR_TOKEN"
You should see a blue-colored embed message appear in #admin.
Test from Django¶
On the production server, verify Django can send notifications:
import os
import requests
# Test backups webhook
url = os.getenv('DISCORD_WEBHOOK_BACKUPS')
if url:
resp = requests.post(url, json={
"embeds": [{"title": "Test from Django", "description": "Backup webhook works!", "color": 3066993}]
}, timeout=10)
print(f"Status: {resp.status_code}")
else:
print("DISCORD_WEBHOOK_BACKUPS not set")
Verification Checklist¶
| Check | Command / Action | Expected Result |
|---|---|---|
#backups webhook works |
curl test (above) | Green embed appears in channel |
#admin webhook works |
curl test (above) | Blue embed appears in channel |
Sentry bot can post to #errors |
Create test Sentry alert (see Sentry guide) | Alert message appears in channel |
Sentry bot can post to #payments |
Create test payment alert (see Sentry guide) | Alert message appears in channel |
| Django can reach webhook | Django shell test (above) | Status 200 printed |
| Env vars are set | docker compose exec backend env \| grep DISCORD |
All webhook URLs shown |
Security Notes¶
- Never commit webhook URLs to version control. They are secrets that allow anyone to post to your channels.
- Store webhook URLs only in
.env.production(which should havechmod 600permissions). - If a webhook URL is compromised, delete the webhook in Discord and create a new one.
- Regenerating a webhook URL invalidates the old one immediately.