Webhooks
Receive secure, organization-wide lifecycle events. Moonitor signs the exact JSON body, retries failures, and keeps every attempt visible for diagnosis.
Set up a receiver
Expose a public HTTPS endpoint
The receiver must return a 2xx response after it has safely accepted the event. Private, loopback and cloud-metadata targets are blocked.
Add it in Moonitor
Open Dashboard → API & webhooks, enter the URL, and subscribe to individual event types or all current and future events.
Copy the signing secret
The
whsec_…secret appears once. Store it securely and use it to verify every delivery before parsing or acting on the data.Send a test
The Test button queues a real
webhook.testevent through the same signing, delivery and attempt-log path as production events.
Payload
{
"id": "msg_…",
"type": "incident.created",
"createdAt": "2026-07-15T12:00:00.000Z",
"data": { "monitor": { "id": "…" }, "incident": { "id": "…" } }
}Use id as your idempotency key. Retries keep the same id and payload.
Event types
| Event | When it fires |
|---|---|
monitor.created | The monitor lifecycle reaches created. |
monitor.updated | The monitor lifecycle reaches updated. |
monitor.deleted | The monitor lifecycle reaches deleted. |
monitor.paused | The monitor lifecycle reaches paused. |
monitor.resumed | The monitor lifecycle reaches resumed. |
monitor.down | The monitor lifecycle reaches down. |
monitor.recovered | The monitor lifecycle reaches recovered. |
incident.created | The incident lifecycle reaches created. |
incident.acknowledged | The incident lifecycle reaches acknowledged. |
incident.resolved | The incident lifecycle reaches resolved. |
status_page.created | The status page lifecycle reaches created. |
status_page.updated | The status page lifecycle reaches updated. |
status_page.deleted | The status page lifecycle reaches deleted. |
maintenance.created | The maintenance lifecycle reaches created. |
maintenance.updated | The maintenance lifecycle reaches updated. |
maintenance.deleted | The maintenance lifecycle reaches deleted. |
webhook.test | A user or API client requests a receiver test. |
Verify signatures
Moonitor follows the Standard Webhooks HMAC-SHA256 format and sends webhook-id, webhook-timestamp and webhook-signature. Sign the exact raw request body; do not parse and re-serialize it first.
import { createHmac, timingSafeEqual } from "node:crypto";
const id = request.headers.get("webhook-id");
const timestamp = request.headers.get("webhook-timestamp");
const signatures = request.headers.get("webhook-signature").split(" ");
const rawBody = await request.text();
const key = Buffer.from(process.env.MOONITOR_WEBHOOK_SECRET.slice(6), "base64");
const expected = createHmac("sha256", key)
.update([id, timestamp, rawBody].join("."))
.digest("base64");
const valid = signatures.some((value) => {
const actual = Buffer.from(value.replace(/^v1,/, ""), "base64");
const wanted = Buffer.from(expected, "base64");
return actual.length === wanted.length && timingSafeEqual(actual, wanted);
});- Reject timestamps more than five minutes away from your current time to limit replay.
- Store each
webhook-idbefore processing so a retry cannot apply the event twice. - During secret rotation, Moonitor signs with both old and new secrets for 24 hours. Accept either valid signature while deploying the new secret.
Delivery and retries
Any 2xx status is success. Redirects, 4xx, 5xx, timeouts and network errors are failures. Moonitor makes up to 6 attempts: the first immediately, then after 30 seconds, 2 minutes, 10 minutes, 1 hours, 6 hours. A reasonable Retry-After response overrides the next delay.
Tip
Acknowledge quickly, then process the event from your own durable queue. Moonitor waits up to 20 seconds for each response.
Operate safely
- Treat signing secrets like API keys. They are encrypted at rest and shown only at create or rotate time.
- Never disable signature verification, even if the endpoint URL is difficult to guess.
- Inspect recent delivery status in Dashboard → API & webhooks; use the public API for every response attempt and diagnostic body.
- Disable or delete an endpoint that is no longer used; revoke leaked API keys immediately.