Skip to content

Webhooks (outbound)

Get a signed HTTPS POST when a board publishes or a screen goes offline/online — the payload shape and how to verify signatures.

Settings → Developer → Webhooks adds an endpoint: a public https URL plus the events you want. Each endpoint gets a signing secret (whsec_…) shown once at creation — store it; we can't show it again. Webhooks are a Pro feature, alongside API access.

Events

  • board.published — a publish (or rollback) cut a new live release. Data: boardId, releaseId, version, feedVersion.
  • device.offline — a paired screen missed heartbeats for 5+ minutes. Data: deviceId, deviceName, boardName, lastSeenAt.
  • device.online — a screen recovered. Data: deviceId, deviceName, boardName.
  • ping — the test event from the dashboard's ping button.

Payload & signature

Every delivery POSTs JSON shaped {id, event, createdAt, data} with headers X-CanvasRelay-Event and X-CanvasRelay-Signature: sha256=<hex>. Verify by computing HMAC-SHA256 of the exact raw request body with your endpoint secret and comparing (timing-safe) to the signature.

import crypto from "node:crypto";

function verify(rawBody: string, signature: string, secret: string): boolean {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Retries & limits

Your endpoint should answer any 2xx within 10 seconds. Failures retry on a backoff — about 1 minute, 5 minutes, 30 minutes, then 2 hours — and stop after 5 attempts. The dashboard shows each endpoint's last delivery status. Endpoints must be public https URLs; private hosts (localhost, .local, private IP ranges) are rejected.