Outgoing Webhooks
Outgoing webhooks send event notifications to your URL when things happen in Monotree. Configure each endpoint and the events it should subscribe to in the Open API → Outgoing Webhooks tab.
Available events
| Event | Fires when |
|---|---|
monotree.post.created | A post is created. |
monotree.comment.created | A comment is added to a post. |
monotree.comment.updated | A comment on a post is edited. |
monotree.comment.deleted | A comment on a post is deleted. |
monotree.announcement.published | An announcement is published. |
monotree.formresponse.created | A form response is submitted. |
monotree.formresponse.updated | A form response's status, deadline, hidden/archived flag, or assignees change. Does not fire on initial creation (use formresponse.created) or for unrelated entities like comments. Filterable by form. Whistleblower forms never dispatch. |
monotree.user.registered | A user accepts an invite and registers. |
monotree.onboarding.completed | A user completes onboarding. |
Payload
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"event": "monotree.post.created",
"version": "v1",
"timestamp": 1711270800,
"payload": {
"id": 123,
"body": "Post content here",
"wall_id": 1,
"wall_name": "General",
"author": { "id": 1, "name": "John Doe", "email": "john@example.com" },
"created_at": "2026-03-22T10:00:00+00:00",
"updated_at": "2026-03-22T10:00:00+00:00"
}
}Signature verification
Every delivery includes two headers:
| Header | Value |
|---|---|
Timestamp | Unix timestamp at the time of delivery. |
Signature | HMAC-SHA256(timestamp + "." + raw_json_body, your_webhook_secret) as a hex string. |
Verify both:
- Recompute the HMAC using your secret and compare it to the
Signatureheader in constant time. - Reject requests whose
Timestampis more than 5 minutes old to prevent replay attacks.
const crypto = require('crypto');
function verify(req, secret) {
const ts = req.headers['timestamp'];
const sig = req.headers['signature'];
const body = req.rawBody; // the raw, unparsed JSON string
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${body}`)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return false;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
return true;
}Authentication
Each webhook can also be configured with one of: Bearer token, Basic Auth, custom API key header, or arbitrary custom headers — useful when your receiver enforces its own auth on top of the signature.
Retries
Failed deliveries (any non-2xx response, or a timeout > 10 seconds) are retried with exponential backoff. Delivery logs are visible in the Outgoing Webhooks tab.