Webhooks

Receive an HTTP POST at your own URL whenever something happens in your chatbot: a new lead, a new conversation, a message, a reply, or a booking.

In short: On Pro and Max, Hyperleap AI webhooks send a signed HTTPS POST to your URL when events happen, such as a lead being captured, a conversation starting, the AI replying or a meeting being booked. Set them up in the Integrations tab.

Webhooks send event data to an HTTPS endpoint you control, as it happens. Use them to push leads into your CRM, log conversations in your own database, or start a process in your backend.

Tip:
Webhooks used to live in a Webhooks tab inside Advanced Settings. They've moved: open your chatbot, go to the Integrations tab, and choose "Webhooks & Zapier".

Prerequisites

  • A Pro or Max plan — On Plus, the section shows the plan you need. You can still view a saved configuration, switch the webhook off, and disconnect subscriptions.
  • A public HTTPS endpoint — The URL must use HTTPS and be reachable from the internet. Local and private network addresses are blocked, and redirects aren't followed, so use the final endpoint URL.
  • A saved chatbot — Save a new chatbot once before you add subscriptions.

Two Ways to Send Events

The Webhooks & Zapier section has two independent ways to deliver events. You can use either or both.

  • Subscriptions — One destination URL per event. A subscription takes effect the moment you create it, with no publishing, and gets its own signing secret.
  • Existing webhook — One URL that receives every event you tick. It's part of your chatbot draft, so changes reach your live chatbot when you save and publish.

Create a subscription

1

Open Webhooks & Zapier

Open your chatbot, select the Integrations tab, and choose "Webhooks & Zapier".
2

Enter the destination and event

Under Subscriptions, paste your URL into "Public HTTPS destination" and pick the Event it should receive.
3

Create it

Click "Create subscription". It starts receiving events immediately.
4

Save the signing secret

The signing secret is shown once, right after you create the subscription. Copy it into your receiver, then click "I have saved the secret". It isn't shown in the subscription list later.
Subscriptions form with Public HTTPS destination, Event picker, and Create subscription button, followed by Inspect event payloads and Delivery history
Subscriptions, event payloads, and delivery history in Integrations → Webhooks & Zapier
Note:
Lost a subscription's secret? Disconnect the subscription and create it again to get a new one. Disconnecting takes effect immediately; discarding your chatbot draft doesn't undo it.

Set up the existing webhook

1

Switch it on and add your URL

Under Existing webhook, turn on the switch and paste your URL into "Public HTTPS destination".
2

Choose events

Tick the events to receive. With none ticked, the webhook receives every supported event.
3

Copy the signing secret

Copy the Signing secret into your receiver. "Regenerate" replaces it immediately, so update your receiver first.
4

Save, test, and publish

Save your chatbot, then click "Test saved existing webhook" to send a test event. The button is disabled while you have unsaved changes. Publish when you're ready for live events to use the new settings.
Existing webhook card with an on/off switch, Public HTTPS destination, event checkboxes, Signing secret with Copy and Regenerate, and Test saved existing webhook
The existing webhook in Integrations → Webhooks & Zapier
Tip:
The existing webhook and your subscriptions can't share a destination URL, so each endpoint is signed with one secret. Use a different URL for each.

Event Types

EventTrigger
lead.capturedA visitor submits the lead form or verifies with OTP
conversation.startedA new conversation is created
conversation.messageThe visitor sends a message
conversation.replyThe AI sends a reply
appointment.bookedThe chatbot books an appointment in the chat (listed once booking is enabled for your chatbot)

Inspect Event Payloads

Under "Inspect event payloads", choose an event to see a sample body. Samples use recent real event data when your chatbot has some, and example data when it doesn't.

Payload reference for developers

Envelope

Every webhook POST body uses this envelope:

{
  "eventType": "lead.captured",        // one of the event types above
  "chatbotId": "a1b2c3d4-...",         // chatbot that triggered the event
  "chatbotName": "Support Bot",        // display name of the chatbot
  "organizationId": "e5f6g7h8-...",    // your organization ID
  "timestamp": "2026-10-15T10:30:00Z", // when the event occurred (ISO 8601 UTC)
  "deliveryId": "d9e0f1a2-...",        // unique ID for this delivery
  "data": { ... }                      // event-specific payload (below)
}

lead.captured

{
  "name": "Jane Smith",               // string | null
  "email": "jane@example.com",        // string | null
  "phone": "+1234567890",             // string | null
  "companyName": "Acme Inc",          // string | null
  "externalUserLoginId": "uuid-...",  // string | null — login record ID
  "externalUserId": "uuid-...",       // the lead; matches externalUserId on conversation events
  "tags": ["enterprise", "demo"],     // string[] | null — conversation tags
  "customFields": { "budget": "5k" }  // custom lead-form answers, keyed by field id
}

conversation.started

{
  "conversationId": "uuid-...",
  "externalUserId": "uuid-...",        // string | null
  "channel": "web",                    // "web", "whatsapp", "instagram" or "facebook"
  "senderExternalId": "15551234567",   // WhatsApp number or Instagram/Messenger ID; absent on web
  "metadata": { "page": "/pricing" }   // object | null — custom metadata from the chat session
}

conversation.message

{
  "conversationId": "uuid-...",
  "message": "How do I reset my password?",  // the visitor's message
  "externalUserId": "uuid-...",
  "channel": "web"
}

conversation.reply

{
  "conversationId": "uuid-...",
  "messageId": "uuid-...",                 // ID of the AI reply
  "userMessage": "How do I reset?",        // the visitor message it answers
  "reply": "To reset your password...",    // the full AI reply
  "externalUserId": "uuid-...",
  "channel": "web"
}

appointment.booked

{
  "conversationId": "uuid-...",
  "externalUserId": "uuid-...",
  "provider": "calcom",                    // the booking calendar's provider
  "calendarId": "...",                     // which calendar, when the chatbot has several
  "meetingType": "Intro call",
  "startUtc": "2026-10-20T15:00:00Z",
  "endUtc": "2026-10-20T15:30:00Z",
  "timeZone": "America/New_York",
  "bookingId": "...",
  "joinUrl": "https://...",
  "cancelUrl": "https://...",
  "attendeeName": "Jane Smith",
  "attendeeEmail": "jane@example.com"
}

Optional fields such as channel, senderExternalId, and the booking details are left out when they don't apply. Lead fields the visitor didn't give are sent as null.

Request Headers

HeaderValueDescription
Content-Typeapplication/jsonAlways JSON
X-Hyperleap-Evente.g. lead.capturedThe event type
X-Hyperleap-Delivery-IdUUID stringUnique delivery ID for idempotency
X-Hyperleap-Signaturesha256={hex}HMAC-SHA256 signature of the body, made with your signing secret

Verifying Signatures

The X-Hyperleap-Signature header carries an HMAC-SHA256 signature of the raw request body, made with the signing secret. Verify it before trusting a request.

Node.js

const crypto = require('crypto');

function verifySignature(payload, secret, signatureHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

Python

import hmac, hashlib

def verify_signature(payload: bytes, secret: str, signature_header: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)
Note:
Use a constant-time comparison (like timingSafeEqual or compare_digest) to prevent timing attacks.

Delivery History

"Delivery history" lists up to 100 recent deliveries with the event, status, and your endpoint's response code. Filter by destination or event, click "Refresh" to load new ones, and open any delivery to see the error and the exact payload sent.

Retries

  • Up to 3 attempts per delivery, with a short, growing wait between them.
  • 10-second timeout per attempt — your endpoint must respond within 10 seconds.
  • What gets retried: timeouts, network errors, and HTTP 5xx, 408, and 429 responses. Other 4xx responses are treated as permanent and aren't retried.
  • HTTP 410 Gone stops delivery for good: the matching subscription is deactivated.

Best Practices

  • Respond with a 2xx status within 10 seconds, and do heavy processing after you've acknowledged the request.
  • Use deliveryId to ignore duplicates: a retry can deliver the same event twice.
  • If a signing secret is ever exposed, regenerate it (existing webhook) or disconnect and recreate the subscription.

Zapier

The same section has an "Automate with Zapier" area. Hyperleap's Zapier app is still in development and isn't public in Zapier's app directory yet. Until it is, use webhooks or the API to connect other tools.

Next Steps

  • Notifications — Get leads and transcripts by email instead
  • CRM MCP — Ask Claude or ChatGPT about your leads
  • API Reference — Full API documentation for programmatic access

Explore Hyperleap AI

An AI front desk that answers customer questions, collects contact details, and books appointments on your website and messaging channels.