Guides

Webhooks

Subscribe to every audited change, verify signatures, handle retries.

Every state-changing action in Panoptes writes one audit row inside its own transaction. When a branch has an active webhook subscription, an event is staged beside that row — so an event is sent if and only if the change committed.

Event names

Events are <module>.<verb>, for example pos.void_line, inventory.post_transfer, hr.run_payroll. The catalogue is served by the Webhooks endpoints.

A subscription may name exact events, a module wildcard (pos.*) or everything (*).

  • Subscribing to hr.*, accounting.* or audit.* requires view_hr, view_gl or view_audit — those payloads carry before-and-after values. * requires all three.
  • Credential and secret lifecycle, evidence views and face registration are never broadcast.

Delivery

Panoptes POSTs to your URL with a JSON body and these headers:

HeaderValue
x-panoptes-signaturesha256=<hex HMAC-SHA256 of the raw body, keyed by the subscription secret>
x-panoptes-event-idUnique event id — use it to de-duplicate
x-panoptes-event-typee.g. pos.create_sale
x-panoptes-api-versionThe subscription's API version
x-panoptes-retry-number0 on the first attempt

Answer any 2xx quickly. Anything else is retried on a backoff ladder; a delivery that keeps failing is marked exhausted and can be replayed from the dashboard.

Verifying the signature

import crypto from 'node:crypto';

function verify(rawBody, header, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return (
    header.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected))
  );
}

Always verify against the raw request bytes, before JSON parsing.

Testing

Use the subscription's Send test action to post a test event to your endpoint, and inspect deliveries (status, response body, attempts) from the same screen.