Agent skill

Oh Dear Webhooks Skill

Receive and verify Oh Dear webhooks. Use when setting up Oh Dear webhook handlers, debugging OhDear-Signature verification, or handling monitoring notifications like httpUptimeCheckFailedNotification, certificateExpiresSoonNotification, brokenLinksFoundNotification, or cronFailedNotification.

Install this skill

npx skills add hookdeck/webhook-skills --skill oh-dear-webhooks


When to Use This Skill

  • How do I receive Oh Dear webhooks?
  • How do I verify the OhDear-Signature header?
  • Why is my Oh Dear webhook signature verification failing?
  • How do I handle uptime, certificate, broken link, or scheduled task notifications from Oh Dear?
  • Why does Oh Dear keep retrying or pause my webhook URL?

Verification (core)

Oh Dear signs the raw request body with HMAC-SHA256, keyed with your team's signing secret, and sends the bare lowercase hex digest in the OhDear-Signature header (no prefix). Nothing else is signed: there is no timestamp or id, so there is no replay window to check. Verify the bytes exactly as received, validate the header format (64 hex characters) before decoding, and compare in constant time.

Node:

const crypto = require('crypto');

function verify(rawBody, signatureHeader, secret) {
  // rawBody is a Buffer (express.raw), never a parsed/re-serialized object
  if (!/^[0-9a-fA-F]{64}$/.test(signatureHeader || '')) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
  const received = Buffer.from(signatureHeader.toLowerCase(), 'hex'); // format already validated
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

Python:

import hashlib, hmac, re

def verify(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
    if not signature_header or not re.fullmatch(r"[0-9a-fA-F]{64}", signature_header):
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
    return hmac.compare_digest(bytes.fromhex(signature_header), expected)

Missing, empty, malformed or mismatched signature: respond 401. Respond 200 directly on success: Oh Dear treats anything other than HTTP 200 (including 301/302 redirects) as a failed delivery.

For complete handlers with route wiring, event dispatch, and tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Common Event Types

Dispatch on the top-level type field of the JSON body (nested objects also have type keys; ignore those).

Event (type)Description
monitorAddedNotificationA monitor was added to the team
httpUptimeCheckFailedNotificationHTTP uptime check failed (tcp... and ping... variants exist)
httpUptimeCheckRecoveredNotificationSite is back up (tcp... and ping... variants exist)
certificateExpiresSoonNotificationTLS certificate is about to expire
brokenLinksFoundNotificationBroken links were found on the site
cronFailedNotificationA scheduled task reported a failure

Oh Dear documents 37 event types in total (performance, mixed content, DNS, application health, sitemap, Lighthouse, AI checks and more). See references/overview.md for the full list.

Important Headers

HeaderDescription
OhDear-SignatureLowercase hex HMAC-SHA256 of the raw body
Content-Typeapplication/json

The body also carries a uuid. A retry or manual Resend keeps the same uuid, so use it for idempotency.

Environment Variables

OH_DEAR_WEBHOOK_SECRET=your_team_signing_secret   # "Web hook signing secret" in Oh Dear notification settings

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 oh-dear --path /webhooks/oh-dear

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 12, 2026

View on GitHub →