WebhooksEvent object

Event object

The JSON envelope and HTTP headers that accompany every webhook delivery from ProductBridge.

Every webhook delivery uses the same JSON envelope. Switch on the event field in your handler to dispatch to the right per-type logic.

Envelope shape

eventstring
Required

The canonical event type. One of the 11 values listed on the Event types page (e.g. post.created, vote.deleted).

organization_idstring
Required

UUID of the organization the event belongs to. Useful when a single receiver handles webhooks from multiple ProductBridge organizations.

occurred_atstring
Required

ISO 8601 timestamp (UTC) at which ProductBridge dispatched the event. Note: this is the dispatch time, not necessarily the moment the underlying business action happened — but they're nearly identical in practice (sub-second).

dataobject
Required

Per-event payload. The shape of data depends on event. See Event types for every variant.

Example delivery

A vote.created event delivery looks like this:

POST /your/webhook/endpoint HTTP/1.1
Host: receiver.example.com
Content-Type: application/json
X-ProductBridge-Event: vote.created
X-ProductBridge-Signature: sha256=ad27c9b1f8e5a2...4f3b
X-ProductBridge-Webhook-Id: 9d2b4e07-5b6f-4d1c-bc11-2f1e0c8a90b1

{
  "event": "vote.created",
  "organization_id": "f5b9b8aa-1b1a-4f1e-9a45-12d8a4a55555",
  "occurred_at": "2026-05-09T12:34:56.789Z",
  "data": {
    "id": "9d2b4e07-5b6f-4d1c-bc11-2f1e0c8a90b1",
    "post_id": "553c3ef8b8cdcd1501ba1238",
    "post_title": "Add dark mode",
    "board_id": "553c3ef8b8cdcd1501ba1234"
  }
}

HTTP headers

ProductBridge sets these headers on every webhook request:

HeaderDescription
Content-TypeAlways application/json.
X-ProductBridge-EventThe event type, mirroring the event field in the body. Useful for routing without parsing the body first.
X-ProductBridge-SignatureHMAC-SHA256 of the raw request body using your webhook's signing secret, hex-encoded with the sha256= prefix. See Webhook signatures.
X-ProductBridge-Webhook-IdUUID of the webhook subscription that generated this delivery. Useful when one receiver serves multiple subscriptions and needs to disambiguate.

Always verify X-ProductBridge-Signature before trusting the body. An unauthenticated webhook URL is a public attack surface — anyone who learns or guesses the URL could otherwise forge events.

Handling the envelope

A typical receiver:

app.post("/webhook", async (req, res) => {
  if (!verify(req)) return res.status(401).end();
  const { event, organization_id, occurred_at, data } = req.body;

  switch (event) {
    case "post.created":
      await handlePostCreated(organization_id, data);
      break;
    case "vote.deleted":
      await handleVoteDeleted(organization_id, data);
      break;
    default:
      // Forward-compatible: just log and 200 unknown event types
      console.log(`Unhandled event: ${event}`);
  }

  res.status(200).end();
});

Always return a 2xx response within 30 seconds, even for unknown event types. Returning a non-2xx triggers retries; consistently failing on events you don't care about wastes resources and may surface as health alarms in your dashboard.