Skip to main content

Guides

Webhooks

Signed event deliveries (Standard Webhooks) for sessions, machines, runs and feedback, with retries and redelivery.

View as Markdown

Webhooks push events to your HTTPS endpoint so you do not have to poll.

Events

EventWhen
session.readyA session became ready
session.failedA session failed
session.closedA session closed
worker.offline / worker.onlineA machine stopped or resumed sending heartbeats
run.completedAn automation run finished
feedback.updatedOne of your feedback tickets changed

Create an endpoint

bash
curl -X POST https://browlix.com/api/public/v1/webhooks \
  -H "Authorization: Bearer $BROWLIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"command_id\":\"$(uuidgen)\",\"url\":\"https://example.com/browlix\",\"events\":[\"session.ready\",\"session.closed\"]}"

The URL must be https:// on a public host name, on port 443, 2053, 2083, 2087, 2096 or 8443. The reply contains the signing secret (whsec_…) once; store it in your secret manager.

Verify every request

Each delivery carries webhook-id, webhook-timestamp and webhook-signature headers (Standard Webhooks v1). Verify the raw body before parsing it:

import { verifyWebhook, WebhookVerificationError } from "@browlix/sdk";

app.post("/browlix", express.text({ type: "application/json" }), async (req, res) => {
  try {
    const event = await verifyWebhook<{ id: string; type: string; data: unknown }>(
      process.env.BROWLIX_WEBHOOK_SECRET!, req.headers, req.body,
    );
    await handleOnce(event); // a repeated webhook-id is the same event redelivered
    res.sendStatus(204);
  } catch (e) {
    res.sendStatus(e instanceof WebhookVerificationError ? 400 : 500);
  }
});

Timestamps more than 5 minutes old or ahead are rejected. Handle each webhook-id once: retries and redeliveries reuse it.

Retries

A delivery that does not get a 2xx within the time limit is retried up to 8 attempts in total, after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours. webhooks.deliveries lists attempts with status and duration; webhooks.redeliver sends a finished delivery again with the same webhook-id; webhooks.test sends one signed webhook.test event.

Rotating the secret

webhooks.rotate_secret returns a new secret once. For overlap_hours the old secret keeps signing too — each request carries both signatures — so your receiver can switch without missing events.