Each webhook delivery includes X-Upmonora-Event, X-Upmonora-Delivery and X-Upmonora-Signature: sha256=<hex>. The signature is an HMAC-SHA256 of the raw request body using your channel's signing secret (shown once when you create the webhook).
PHP
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, getenv('UPMONORA_WEBHOOK_SECRET'));
$given = $_SERVER['HTTP_X_UPMONORA_SIGNATURE'] ?? '';
if (!hash_equals($expected, $given)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($body, true);
// $event['event'] === 'monitor.down', $event['monitor'], $event['incident'] …
http_response_code(204);
Node.js (Express)
import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/webhooks/upmonora', express.raw({ type: 'application/json' }), (req, res) => {
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.UPMONORA_WEBHOOK_SECRET)
.update(req.body).digest('hex');
const given = req.get('X-Upmonora-Signature') || '';
const ok = given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
if (!ok) return res.status(401).send('Invalid signature');
const event = JSON.parse(req.body);
console.log(event.event, event.monitor);
res.sendStatus(204);
});
Tips
- Always verify against the raw body, before JSON parsing.
- Return a 2xx quickly; non-2xx responses are retried with back-off.
- Use
X-Upmonora-Deliveryto de-duplicate retries.