((w))ebinaric

Search documentation

Search the Webinaric docs

Start free

Webhooks

Push webinar activity and configuration changes to your own systems as signed, batched HTTP requests.

On this page

Webhooks send what happens in your webinars to a URL you run. That covers registrations, leads, sessions, questions, clicks and conversions. Use them to feed a CRM, an automation tool such as Zapier, a data warehouse or your own backend. Deliveries are JSON, batched, signed with the Standard Webhooks scheme and retried when your endpoint is down.

Set up a webhook

Webhooks belong to a workspace. Owners and admins can create, edit, test and delete them and see their signing secrets. Other members can view webhooks and their delivery logs.

  1. Create the webhook

    Open Settings → Webhooks and click New webhook. Give it a Name, an optional Description and the Endpoint URL that should receive events. The endpoint must be reachable from the public internet.

  2. Choose events

    Under Events, tick the event types to send. Select all picks a whole group. Pick an "All …" option, such as All session events, to also receive event types added to that family later.

  3. Limit to some webinars (optional)

    Under Webinar access, pick the webinars whose activity should be sent. By default every webinar in the workspace is included. Allow all webinars instead removes the limit.

  4. Save the secret

    Click Create webhook. The signing secret (whsec_…) is shown once. Store it where your endpoint can read it. Owners and admins can reveal it again later on the webhook's Overview tab.

  5. Send a test

    On Overview, use Send a test event to post a sample of any event type to your endpoint right away. The test shows the HTTP status, timing and response body. Subscriptions don't apply to tests.

Set Status to Disabled to pause a webhook without deleting it.

Events

Webinar activity

These events can be limited to specific webinars with Webinar access.

EventSent whenTiming
registration.createdA visitor joins from the lobby. Carries name, email (when asked), visitor ID, the session and attribution. emailVerified is true when they joined from a link mailed to that email.Right away
registration.scheduledA visitor registers for a scheduled time or moves to another time. Carries the time, and the previous time on moves.Right away
registration.pendingA visitor asks for a join link in a lobby that verifies emails. Carries name, email (not yet verified), the registration ID and attribution. registration.created follows each time they join from the link.Right away
lead.capturedAn email becomes known for a participant, from the lobby form or given in the chat. Carries the email source and the lead's score and tier.Right away from the lobby. With the session report when given in the chat.
session.startedThe presenter starts on the first slide. Can trail the join by a few seconds.With the session report
session.finishedThe webinar runs to the end. Carries the session summary and every participant's engagement.With the session report
session.abandonedEveryone left before the end and the session went idle. Same payload as finished.With the session report
participant.joinedA participant shows up in a sessionWith the session report
question.askedA participant asks a question in the chatWith the session report
question.answeredThe presenter answers a question (answeredBy: "agent"), or your team answers one from the Inbox (answeredBy: "operator")With the session report, or right away from the Inbox
link.clickedA participant clicks an offer button or a chat link. Bots are skipped.Right away
conversion.recordedA conversion arrives through the snippet or the conversion API, with the webinar and session it was credited to, if anyRight away
lobby.viewedA new visitor opens a lobby page. High volume, so subscribe only if you need page views.Right away

Configuration changes

These events are always sent, whatever Webinar access says. They carry the webinar or webhook and the member who made the change.

EventSent when
config.webinar.createdA webinar is created or duplicated
config.webinar.publishedA version goes live: first publish, republish or rollback
config.webinar.deletedA webinar is deleted
config.webhook.created, config.webhook.updated, config.webhook.deletedA webhook is created, updated (including secret rotation and quarantine release) or deleted. Payloads never contain signing secrets.

System events

webhook.test (test sends) and webhook.rate_limited are always delivered and can't be unsubscribed. webhook.rate_limited tells you when events were dropped, with reason, droppedEvents and bufferedEvents.

Payload

Each delivery is a POST with Content-Type: application/json and a JSON body that holds one or more events:

JSON
{  "version": 1,  "events": [    {      "id": "evt-01JBX6ZK4V8R2N3QF5T7W9Y0AB",      "type": "registration.created",      "time": "2026-11-04T09:30:12.000Z",      "workspace": "ws_7hQ2kLm",      "data": {        "webinarId": "wb_4Nf8sXp",        "webinarTitle": "Scale Your SaaS: 2026",        "sessionId": "ses_9Qe2vRt",        "participantId": "p_k3J8dLw2",        "name": "Alex Example",        "email": "alex@example.com",        "visitorId": "v_3f2a9c1e-6b7d-4e2f-9a10-5c8d7e6f4b21",        "attribution": {          "referrer": "https://www.linkedin.com/",          "utm": {            "utm_source": "linkedin",            "utm_medium": "paid-social",            "utm_campaign": "q4-pipeline-webinar"          },          "clickIds": { "li_fat_id": "a1b2c3d4" }        }      }    },    {      "id": "evt-01JBX6ZK4V8R2N3QF5T7W9Y0AC",      "type": "lead.captured",      "time": "2026-11-04T09:30:12.000Z",      "workspace": "ws_7hQ2kLm",      "data": {        "webinarId": "wb_4Nf8sXp",        "sessionId": "ses_9Qe2vRt",        "participantId": "p_k3J8dLw2",        "name": "Alex Example",        "email": "alex@example.com",        "emailSource": "lobby",        "visitorId": "v_3f2a9c1e-6b7d-4e2f-9a10-5c8d7e6f4b21",        "lead": { "key": "alex@example.com", "score": 12, "tier": "cold" }      }    }  ]}

The IDs above are illustrative. Some things to know about payloads:

  • Batching. A delivery holds up to 100 events. Loop over events.
  • Optional fields are left out when empty, rather than sent as null.
  • Times are ISO 8601 in UTC.
  • No IP addresses. Participant payloads carry country, device and userAgent instead.
  • Duplicates are possible. Delivery is at least once, so use each event's id to ignore repeats.

The full contract for every event type is a JSON Schema at /schemas/webhook-events-v1.json. It is also linked as JSON Schema on the Settings → Webhooks page.

Verify signatures

Every delivery carries three headers:

HeaderValue
webhook-idThe delivery ID. It stays the same across retries of the same delivery.
webhook-timestampUnix time in seconds when this attempt was sent
webhook-signatureOne or more space-separated v1, + base64 signatures

The signature is an HMAC-SHA256 of webhook-id, webhook-timestamp and the raw body joined with dots. The key is the base64-decoded part of the secret after whsec_. Any Standard Webhooks library can verify it. Here is the check in plain Node.js:

JavaScript
import crypto from "node:crypto"; // rawBody: the request body as a string, exactly as received (before JSON.parse)export function verifyWebinaricWebhook(rawBody, headers, secret) {  const id = headers["webhook-id"];  const timestamp = headers["webhook-timestamp"];  const signatures = headers["webhook-signature"] ?? "";   // reject old or future timestamps (5 minutes) to block replays  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;   const key = Buffer.from(secret.slice("whsec_".length), "base64");  const expected = crypto    .createHmac("sha256", key)    .update(`${id}.${timestamp}.${rawBody}`)    .digest("base64");   return signatures.split(" ").some((value) => {    const [version, signature] = value.split(",");    return (      version === "v1" &&      signature?.length === expected.length &&      crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))    );  });}

Rotating the secret

On Overview, Rotate creates a new secret. For 24 hours, deliveries are signed with both the new and the previous secret, so webhook-signature holds two values. Update your endpoint within that window. A check that accepts any matching value, like the one above, keeps working throughout.

Retries and quarantine

Your endpoint should answer with a 2xx status within 10 seconds. Anything else counts as a failure, including timeouts and redirects, which are never followed.

  • A failed delivery is retried after 30 seconds, 2 minutes, 10 minutes, 30 minutes and 1 hour. That makes 6 attempts over about 1 hour 45 minutes, all with the same webhook-id.
  • On 429 and 503, a Retry-After header is honored, up to 1 hour.
  • Each endpoint gets at most about 5 deliveries per second.

If the last attempt fails, that batch is dropped and the webhook is quarantined for 24 hours. Organization owners get an email, and the webhook shows "Deliveries paused until …". New events keep buffering during quarantine and are delivered when it ends. Owners and admins can click Release now to resume early. If the buffer overflows, the oldest events are dropped and a webhook.rate_limited event reports how many.

Delivery log and metrics

Each webhook has three tabs:

  • Overview: subscribed events, the webinar scope, Send a test event and Signing secret.
  • Deliveries: recent deliveries with status, response code, event count and types, attempts and duration. Click one to see the full payload and your endpoint's response. Responses are cut at 4 KB.
  • Metrics: Delivered, Failed attempts, Events sent and Events dropped, with charts for deliveries, events and delivery latency over the last hour up to 7 days.