Agent skill
Datto RMM Webhooks Skill
Receive and authenticate Datto RMM Global Webhooks. Use when setting up a Datto RMM webhook endpoint, checking the secret header you add to a Global Webhook, debugging 401s, or handling alert raised and alert resolved payloads from a custom template.
Install this skill
npx skills add hookdeck/webhook-skills --skill datto-rmm-webhooks
Datto RMM sends an HTTP POST when a monitor alert is raised and, optionally, when it is resolved. Requests are not signed. You authenticate them with a secret header that you add to the Global Webhook yourself (Add Header), and your endpoint compares that header with the value it has stored. The body is a template you write, using [variable] substitutions.
Use Global Webhooks. Per-monitor webhooks can't carry a secret header. Turning on Global Webhooks (Setup > Integrations > Global Webhooks) disables the webhooks set on individual monitors.
When to Use This Skill
- How do I receive Datto RMM webhooks?
- Does Datto RMM sign webhook payloads? (No: use a secret header)
- How do I authenticate a Datto RMM Global Webhook with a custom header?
- How do I handle alert raised and alert resolved payloads?
- Why does my Datto RMM webhook endpoint return 401?
Verification (core)
const crypto = require('crypto');
// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
const ha = crypto.createHash('sha256').update(String(a)).digest();
const hb = crypto.createHash('sha256').update(String(b)).digest();
return crypto.timingSafeEqual(ha, hb);
}
function verifyDattoRmmRequest(headers, {
headerName = process.env.DATTO_RMM_WEBHOOK_HEADER || 'Authorization',
secret = process.env.DATTO_RMM_WEBHOOK_SECRET,
} = {}) {
if (!secret) return false; // never accept when unconfigured
const received = headers[headerName.toLowerCase()]; // Node lowercases header names
return Boolean(received) && safeEqual(received, secret); // WHOLE value, no prefix parsing
}
- The header name is whatever you typed in Add Header; the examples read it from
DATTO_RMM_WEBHOOK_HEADER(defaultAuthorization) and look it up case-insensitively. DATTO_RMM_WEBHOOK_SECRETis the exact, whole header value, including anyBearerprefix you typed. Do not strip or parse a prefix; compare the whole string.- Missing header or mismatch: return
401. Otherwise200once handled. - Read the body raw (
express.raw({ type: '*/*' })) and parse it only after the check. The content type can be JSON,text/plainorapplication/x-www-form-urlencoded, so don't reject non-JSON bodies. - A static shared credential authenticates the sender, not the body. There is no signature and no timestamp, so it gives no replay protection. Use HTTPS, and rotate the credential (in Datto RMM and in your environment) if it leaks.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Payload (illustrative)
Datto RMM adds no event field. The body is your own template, with separate templates for alert raised and alert resolved. The examples assume you write a status field into each template. This payload is an illustration, not a vendor schema:
{
"status": "raised",
"alert_uid": "[alert_uid]",
"alert_type": "[alert_type]",
"alert_category": "[alert_category]",
"alert_message": "[alert_message]",
"device_hostname": "[device_hostname]",
"site_name": "[site_name]"
}
Use "status": "resolved" in the alert resolved template. Supported variables include [device_id], [device_uid], [device_hostname], [device_os], [device_ip], [site_id], [site_name], [alert_uid], [alert_type], [alert_category], [alert] and [alert_message] (see references/overview.md).
Environment Variables
DATTO_RMM_WEBHOOK_HEADER=Authorization # name of the header you added (default Authorization)
DATTO_RMM_WEBHOOK_SECRET=your-secret # exact, whole header value
Local Development
Datto RMM can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 datto-rmm --path /webhooks/datto-rmm
Use the printed URL as the Global Webhook URL (max 500 characters).
Resources
- references/overview.md - What Datto RMM webhooks are, templates and variables
- references/setup.md - Turn on Global Webhooks and add the secret header
- references/verification.md - Header check details, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests