Community. Driven. Weather. Data. | Always Ad-Free | Developer FriendlyChecking statusDiscord
Become a supporter
Sign in

Send alerts to Discord, Slack, Teams or your own server

Post the alerts for your places to a Discord, Slack, Microsoft Teams or Google Chat channel, or to any HTTPS endpoint, and verify the signed JSON on your side.


A webhook posts each alert for your places to a chat channel or a server you run. One webhook can cover several places, and one place can feed several webhooks. Webhooks are free on every plan.

Add one

  1. Create an incoming webhook in the destination and copy its URL:
    • Discord: Channel settings, Integrations, Webhooks, New Webhook.
    • Slack: an app with Incoming Webhooks turned on, added to the channel.
    • Microsoft Teams: the Workflows app, “Post to a channel when a webhook request is received”.
    • Google Chat: Space settings, Apps and integrations, Webhooks.
    • Anything else (Zapier, IFTTT, your own code): any public HTTPS URL.
  2. On your account, open Webhooks and choose Add a webhook.
  3. Name it, pick the type, paste the URL and tick the places it covers.
  4. Choose Save and send test to post a test message straight away.

The type is checked against the URL, so a Slack address cannot be saved as Discord. After saving, the URL is shown only by its host.

What gets posted

One message per alert per webhook. When an alert covers several of the webhook’s places, the one message names them all (“Tornado Warning for Home, Shop and Barn”). Each chat platform gets its own format: a Discord embed, Slack Block Kit, a Teams card or a Google Chat card, with the headline, a colour for the severity, when it ends and a link to the alert. Discord messages never ping @everyone or a role.

When delivery fails

A busy or briefly down receiver is retried five times over about fifty minutes, and never sooner than its own Retry-After asks. A URL that answers “not found” or “forbidden” is not retried. After three alerts in a row fail to land, the webhook shows Delivery failing and you get one email. The next success clears it.

Generic webhooks

Anything that is not a chat platform gets versioned JSON:

{
  "type": "alert",
  "version": 2,
  "event_id": "5f0c1c8e-0d0e-4b7a-9b7e-2f1d8c6a4e11",
  "alert": {
    "id": "urn:oid:2.49.0.1.840.0.example",
    "event": "Tornado Warning",
    "headline": "Tornado Warning issued for Santa Rosa County until 4:15 PM CDT",
    "significance": "W",
    "severity": "Extreme",
    "issued_at": "2026-04-02T20:41:00Z",
    "ends_at": "2026-04-02T21:15:00Z",
    "link": "https://wxalerts.org/alerts/..."
  },
  "place": { "id": 12, "label": "Home" },
  "places": [{ "id": 12, "label": "Home" }, { "id": 14, "label": "Shop" }],
  "branding": "Alerts by WxAlerts.org"
}

event_id is the same on every retry of one message, so use it to ignore a retry you already handled. place is the first place, kept for receivers built on version 1; read places. A test message has "type": "test".

Verify the signature

The signing secret is shown once, when you create the webhook. Save it then. Every request carries three headers:

  • X-WxAlerts-Timestamp: Unix seconds.
  • X-WxAlerts-Signature: sha256= and the hex HMAC-SHA256 of timestamp + "." + raw body, keyed with the secret.
  • X-WxAlerts-Delivery: the delivery’s id, also the same on every retry.
import hashlib, hmac, time

def verify(secret: str, timestamp: str, signature: str, body: bytes) -> bool:
    if abs(time.time() - int(timestamp)) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Reject anything that fails. Without this check, anyone who learns the URL can post a fake warning to it.

If you show these alerts to people, credit WxAlerts.org; the branding field carries the line to use.

View this page as Markdown

May we use Microsoft Clarity to see how pages are used (clicks, scrolling and replays of a visit, with anything you type hidden), plus a random ID linking that to crash reports? Only to find bugs and confusing screens. Never advertising, never sold.