Onboard webhooks

When Hosted progress changes, you may want Slack or your own worker notified, without shipping host context or flags through the wire.

Onboard webhooks carry operational identifiers only. Configure an HTTPS endpoint in the dashboard (webhooks are dashboard-only, not MCP).

Events

EventWhen
onboard.flow_startedHosted flow first evaluated for this user. Data: flowId, userId, workspaceKey, revision.
onboard.item_completedHosted step completed. Ids and stepKey only.
onboard.item_skippedOptional step skipped. Ids and stepKey only.
onboard.flow_completedRequired items satisfied. Does not fire on dismiss.
onboard.flow_dismissedUser dismissed the widget. Not 100% complete.
onboard.flow_snoozedUser snoozed. Data includes until timestamp as an id/time, not host flags.
onboard.flow_resumedSnooze or dismiss cleared.
onboard.progress_resetPersonal generation bumped. Shared workspace steps stay.

Envelope fields also include workspaceId, productId (onboard), and timestamp. Reference: webhooks docs.

BYO adapters keep progress on your backend and do not emit these Bootstrapware Onboard webhooks for your store. Use onEvent on the widget instead.

Signature

Deliveries POST JSON and sign the raw body with HMAC-SHA256. The hex digest is sent as header X-Bootstrapware-Signature. A failed delivery is retried once.

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

function verifyBootstrapwareSignature(
  rawBody: string,
  header: string | null,
  secret: string,
) {
  if (!header) return false;
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(header, "hex");
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}

Parse JSON only after verification. Do not re-serialize the body before hashing.

Related: Webhooks docs · Security · API overview · Summaries