Skip to main content

Webhooks

Webhooks deliver engagement events to your backend over HTTPS — the server-to-server counterpart to the SSE stream. You register an endpoint, RSMG Engage POSTs signed JSON to it, and you verify the signature before trusting the payload.

Register an endpoint

Create endpoints in the console, or via POST /api/v1/admin/webhooks (admin / moderate_content). Choose which event types to receive, or use * for all. The subscribable events are:

comment_created, comment_edited, comment_deleted, comment_approved, comment_rejected, comment_pinned, comment_unpinned, reaction_toggled, discussion_locked, discussion_unlocked, discussion_archived.

Delivery headers

POST <your-url>
Content-Type: application/json
X-RSMG-Engage-Signature: t=<unix>,v1=<hex>,kid=<8-hex>
X-RSMG-Engage-Timestamp: <iso-8601>
X-RSMG-Engage-Event: <event-name>
X-RSMG-Engage-Delivery-Id: <uuid>
X-RSMG-Engage-Idempotency-Key: <event>:<source-id>

Verify the signature

The scheme mirrors identity signing: HMAC-SHA256 with the endpoint's secret. Here, though, the signed payload is ${timestamp}.${rawBody} — the raw request body bytes as received, not a re-serialized copy.

import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(headers, rawBody, secret) {
const ts = headers['x-rsmg-engage-timestamp'];
const parts = Object.fromEntries(
headers['x-rsmg-engage-signature'].split(',').map((p) => p.split('=', 2)),
);
const expected = createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(parts.v1 ?? '', 'hex');
return a.length === b.length && timingSafeEqual(a, b);
}
  • Capture the raw body before any JSON parsing or re-serialization — re-encoding changes the bytes and breaks verification.
  • Reject deliveries whose timestamp is older than a few minutes, as replay protection.
  • kid identifies which secret to use — important during secret rotation, which keeps a 24-hour overlap, like identity signing.

Idempotency, retries & circuit breaking

  • X-RSMG-Engage-Idempotency-Key is stable across retries of the same event, so dedupe on it.
  • Failed deliveries are retried with backoff. Persistent failures trip a per-endpoint circuit breaker, and a long run of failures auto-disables the endpoint — re-enable it in the console.
  • Return a 2xx quickly and do slow work asynchronously, so you don't trip the breaker.

The full payload shape for each event is under Webhooks in the API Reference.