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-Signatureheader? - 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 |
|---|---|
monitorAddedNotification | A monitor was added to the team |
httpUptimeCheckFailedNotification | HTTP uptime check failed (tcp... and ping... variants exist) |
httpUptimeCheckRecoveredNotification | Site is back up (tcp... and ping... variants exist) |
certificateExpiresSoonNotification | TLS certificate is about to expire |
brokenLinksFoundNotification | Broken links were found on the site |
cronFailedNotification | A 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
| Header | Description |
|---|---|
OhDear-Signature | Lowercase hex HMAC-SHA256 of the raw body |
Content-Type | application/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
- references/overview.md - Oh Dear webhook concepts, delivery rules, all event types
- references/setup.md - Configure the webhook URL and find the signing secret
- references/verification.md - Signature verification details and debugging