Webhooks

Get alerts as signed JSON POST requests to any URL you control.

Overview

Webhooks let your own systems react to monitoring events. When a monitor goes down, comes back up, or its SSL certificate is about to expire, Notifier sends an HTTP POST with a JSON body to the URL you choose. Use them to open tickets, trigger runbooks, post to chat tools we don't integrate with yet, or feed your own dashboards.

Webhooks are available on Solo ($4/mo) and above.

Adding a Webhook

  1. Go to Integrations in the monitoring dashboard.
  2. In the Webhooks section, click Add webhook.
  3. Enter a name and the URL that should receive events (http or https).
  4. Choose the events to send: monitor down, monitor up, SSL expiring.
  5. Under Which monitors?, choose All monitors (including ones you add later) or Only selected monitors and tick them. You can also add or remove a webhook from a monitor in that monitor's Notifications settings.
  6. Optionally add up to 10 custom headers, such as an Authorization token your endpoint expects.
  7. Save, copy the signing secret, and click Send test to check your endpoint.
Only team owners can add or change webhooks. Custom header values and the signing secret are encrypted at rest.

Pushover and ntfy

To get alerts as push notifications on your phone, pick a ready-made Format when you add the webhook. Notifier then sends the request each app expects, with a readable title, the monitor's address and a link to the incident. You don't need to build anything.

Pushover

  1. Copy your user key from the top of your pushover.net dashboard.
  2. On pushover.net, choose Create an Application/API Token, name it Notifier, and copy its API token.
  3. In Notifier, add a webhook, choose the Pushover format and paste both. There's no URL to enter.

Down alerts are sent with high priority, so they bypass quiet hours. Recovery, SSL and test alerts use normal priority.

ntfy

  1. Pick a hard to guess topic name and subscribe to it in the ntfy app.
  2. In Notifier, add a webhook, choose the ntfy format and enter the topic URL, for example https://ntfy.sh/your-topic. Self-hosted ntfy servers work too.
  3. For a protected topic, add a custom header named Authorization with the value Bearer tk_... (your ntfy access token).

Down alerts use ntfy's highest priority, SSL warnings high priority, and recoveries and tests the default.

Pushover and ntfy requests aren't signed, since those apps don't check signatures. Everything else on this page (events, retries, the delivery log and auto-pause) works the same.

Events

  • monitor.down: a monitor failed its checks and an incident was opened.
  • monitor.up: the monitor recovered and the incident was resolved.
  • ssl.expiring: the monitor's SSL certificate crossed a warning threshold (30, 14, 7 or 1 days before expiry).
  • test: sent only when you click Send test.

Payload

Every request has Content-Type: application/json. A monitor.down event looks like this:

{
  "event_id": "9771f505-ce7c-4f85-9d02-c45a43cea464",
  "event": "monitor.down",
  "occurred_at": "2026-10-21T14:03:12Z",
  "monitor": {
    "id": 1155,
    "name": "My website",
    "type": "http",
    "url": "https://example.com",
    "hostname": null,
    "port": null,
    "dashboard_url": "https://notifier.so/new/monitoring"
  },
  "incident": {
    "id": 48211,
    "status": "ongoing",
    "started_at": "2026-10-21T14:03:12Z",
    "ended_at": null,
    "duration_seconds": null,
    "url": "https://notifier.so/new/monitoring/incidents/incident?id=48211"
  }
}

monitor.up has the same shape with "status": "resolved", ended_at and duration_seconds filled in. ssl.expiring has an ssl object instead of incident:

"ssl": {
  "expires_at": "2026-11-04T23:59:59Z",
  "days_remaining": 14,
  "issuer": "Let's Encrypt"
}

Times are UTC in ISO 8601. New fields may be added over time, so ignore fields you don't recognize.

Request Headers

  • X-Notifier-Event: the event type, for example monitor.down.
  • X-Notifier-Delivery: the event ID. It stays the same on every retry, so use it to ignore duplicates.
  • X-Notifier-Attempt: the attempt number, starting at 1.
  • X-Notifier-Signature: the signature described below.
  • User-Agent: Notifier-Webhooks/1.0.

Verifying Signatures

Each request is signed with your webhook's secret (it starts with whsec_). The header looks like t=1761055392,v1=5257a8..., where v1 is the hex HMAC SHA256 of the timestamp, a period, and the raw request body. To verify:

  1. Read the raw body before parsing the JSON.
  2. Compute HMAC SHA256 with your secret over "{t}.{raw body}".
  3. Compare it to v1 with a constant time comparison.
  4. Reject requests whose timestamp is more than 5 minutes old to block replays.

Python

import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(item.split("=", 1) for item in header.split(","))
    t = int(parts["t"])
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Node.js

const crypto = require("crypto");

function verify(secret, header, rawBody, tolerance = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (Math.abs(Date.now() / 1000 - t) > tolerance) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const given = Buffer.from(parts.v1 || "");
  return given.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), given);
}

You can reveal or rotate the secret from the webhook's settings. Rotating takes effect immediately.

Responses and Retries

  • Any 2xx response within 10 seconds counts as delivered. Respond quickly and do slow work in the background.
  • Redirects are not followed. Use the final URL.
  • Failed deliveries are retried up to 5 attempts in total: right away, then after 30 seconds, 2 minutes, 10 minutes and 30 minutes. Every attempt carries the same event ID.
  • If an endpoint fails every delivery for 48 hours, Notifier pauses it and emails the team owner. Your other alert channels keep working. Turn the webhook back on once it's fixed.
  • Each endpoint accepts up to 60 deliveries per minute.

Delivery Log

Open a webhook's deliveries to see every attempt from the last 30 days: time, event, attempt number, status code, response time, error, the payload we sent and the start of your response. Click Resend to send an event again with the same event ID.

Security Notes

  • Webhook URLs must resolve to public internet addresses. Private, loopback and cloud metadata addresses are rejected.
  • Credentials inside the URL (https://user:pass@...) are not allowed. Use a custom header instead.
  • Always verify the signature before trusting a request.

Plan Availability

Plan Webhooks
FreeNot available
SoloAvailable
TeamAvailable
EnterpriseAvailable