Embed SDK
Available on all plans

Widget JavaScript Events

Every action a user takes inside the booking widget fires a typed JavaScript event. Listen with window.ConsultGen.on() for a global bus, or with element.addEventListener() when you have multiple widgets on the page.

Quick start - add this before widget.js

<!-- Add this BEFORE widget.js loads so no events are missed -->
<script>
  window.ConsultGen = window.ConsultGen || {
    _q: [],
    on: function (event, fn) { this._q.push([event, fn]) },
  }
</script>
<script src="https://cdn.consultgen.app/widget.js" async></script>

Why the stub? The pre-stub queues any on() calls made before widget.js has finished loading. The SDK drains the queue on init so no events are missed.

2 widget lifecycle events
4 booking funnel events
1 contact & identity event
3 payments events

Widget Lifecycle

Booking Funnel

Contact & Identity

Payments

AI Assistant Webhooks

These server-to-server events are made for AI Receptionist and Smart Inbox Pro workflows. They help you wake up a CRM, notify your team, or close the loop automatically without depending on browser-side JavaScript.

Delivery headers

X-ConsultGen-Event: enquiry.created | chat.resolved
X-ConsultGen-Signature: <hex hmac sha256 signature>
Content-Type: application/json

Verify the signature

import crypto from 'node:crypto'

export function verifyConsultGenSignature(rawBody, signatureHeader, webhookSecret) {
  const expected = crypto
    .createHmac('sha256', webhookSecret)
    .update(rawBody, 'utf8')
    .digest('hex')

  return crypto.timingSafeEqual(
    Buffer.from(expected, 'utf8'),
    Buffer.from(signatureHeader || '', 'utf8'),
  )
}
AI Assistant webhook
enquiry.created

Sent when the AI Assistant captures a handover enquiry and pushes the visitor into human follow-up.

When it fires

This fires after the visitor submits their details for sales or support handover.

Why it matters

Use it to create or update a lead in your CRM, notify a human agent quickly, or kick off a fast welcome sequence while intent is still hot.

Payload

FieldTypeDescription
data.enquiry_idstringThe saved enquiry UUID.
data.session_idstringThe related chat session UUID.
data.crm_contact_idstring | nullCRM contact UUID if one was linked.
data.enquiry_kind'general' | 'specialist' | 'purchase'The kind of handover the assistant classified.
data.namestringVisitor name from the handover form.
data.emailstringVisitor email address.
data.phonestring | nullVisitor phone number if supplied.
data.companystring | nullVisitor company if supplied.
{
  "event": "enquiry.created",
  "organization_id": "org_uuid",
  "occurred_at": "2026-07-28T09:08:57.192Z",
  "data": {
    "enquiry_id": "enquiry_uuid",
    "session_id": "session_uuid",
    "crm_contact_id": "contact_uuid",
    "enquiry_kind": "purchase",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+27 82 555 0101",
    "company": "Acme Studio"
  }
}
AI Assistant webhook
chat.resolved

Sent when a chat is closed, whether that happens from the staff side or when the visitor ends the conversation.

When it fires

This fires once the chat session is moved into a resolved state and the final visitor rating, if any, has been saved.

Why it matters

Use it to close tickets, move a CRM contact into a resolved stage, trigger a follow-up survey, or measure how many chats ended on a strong note.

Payload

FieldTypeDescription
data.session_idstringThe resolved chat session UUID.
data.scope'marketing' | 'support'Which queue the conversation belonged to.
data.visitor_ratingnumber | nullThe final visitor rating when feedback was submitted.
{
  "event": "chat.resolved",
  "organization_id": "org_uuid",
  "occurred_at": "2026-07-28T09:08:57.192Z",
  "data": {
    "session_id": "session_uuid",
    "scope": "marketing",
    "visitor_rating": 5
  }
}