v1.0 • Lead Management
Receive real-time notifications when events occur in your chatbot using secure webhooks.
Webhooks allow your application to receive real-time notifications when specific events occur in your chatbot. When an event is triggered, Pollybot will send an HTTP POST request to your webhook URL with details about the event.
All webhook payloads are signed with HMAC SHA256 using a secret key unique to each webhook. You should always verify the signature to ensure the request came from Pollybot.
The signature is sent in the X-Webhook-Signature header in the format sha256=<signature>
const crypto = require('crypto');
function verifyWebhookSignature(body, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
const receivedSignature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}
// Usage in Express.js
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = 'your-webhook-secret';
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook payload
const payload = JSON.parse(req.body);
res.status(200).send('OK');
});import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
def verify_webhook_signature(body, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
body,
hashlib.sha256
).hexdigest()
received_signature = signature.replace('sha256=', '')
return hmac.compare_digest(expected_signature, received_signature)
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Webhook-Signature')
secret = 'your-webhook-secret'
if not verify_webhook_signature(request.data, signature, secret):
return 'Invalid signature', 401
# Process the webhook payload
payload = request.json
print(f"Received event: {payload['event']}")
return 'OK', 200Triggered when a new lead is created for your chatbot.
{
"event": "LEAD_CREATED",
"timestamp": 1699123456,
"data": {
"id": "clp123abc456",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"company": "Acme Corp",
"message": "Interested in your services",
"preferredMethod": "email",
"urgency": "medium",
"source": "chat_widget",
"status": "NEW",
"priority": "MEDIUM",
"tags": ["website", "inquiry"],
"customFields": {
"budget": "10000",
"timeline": "Q1 2024"
},
"chatbotId": "clp123chatbot456",
"createdAt": "2023-11-04T15:30:56.789Z",
"updatedAt": "2023-11-04T15:30:56.789Z"
},
"chatbotId": "clp123chatbot456"
}Additional events like LEAD_UPDATED, CONVERSATION_STARTED, and CONVERSATION_RESOLVED will be available in future releases.
All webhook API endpoints require session authentication. You must be logged in to your Pollybot account and own the chatbot to access these endpoints. API keys are not currently supported - use session cookies from your logged-in browser session.
/api/v1/chatbots/{chatbotId}/webhooksList all webhooks for a chatbot.
{
"webhooks": [
{
"id": "webhook_123",
"name": "Lead Notifications",
"url": "https://yourapp.com/webhooks/leads",
"eventTypes": ["LEAD_CREATED"],
"isActive": true,
"maxRetries": 3,
"retryDelay": 1000,
"successCount": 25,
"failureCount": 2,
"lastTriggeredAt": "2023-11-04T15:30:56.789Z",
"lastSuccessAt": "2023-11-04T15:30:56.789Z",
"createdAt": "2023-11-01T10:00:00.000Z",
"updatedAt": "2023-11-04T15:30:56.789Z"
}
],
"total": 1
}/api/v1/chatbots/{chatbotId}/webhooksCreate a new webhook.
{
"name": "Lead Notifications",
"url": "https://yourapp.com/webhooks/leads",
"eventTypes": ["LEAD_CREATED"],
"maxRetries": 3,
"retryDelay": 1000
}{
"message": "Webhook created successfully",
"webhook": {
"id": "webhook_123",
"name": "Lead Notifications",
"url": "https://yourapp.com/webhooks/leads",
"secret": "whsec_1234567890abcdef...",
"eventTypes": ["LEAD_CREATED"],
"isActive": true,
"maxRetries": 3,
"retryDelay": 1000,
"successCount": 0,
"failureCount": 0,
"createdAt": "2023-11-04T15:30:56.789Z",
"updatedAt": "2023-11-04T15:30:56.789Z"
},
"security": {
"note": "Store the secret securely. It will not be shown again.",
"headerName": "X-Webhook-Signature",
"format": "sha256=<hmac_signature>"
}
}/api/v1/chatbots/{chatbotId}/webhooks/{id}Update an existing webhook.
{
"name": "Updated Lead Notifications",
"isActive": false
}/api/v1/chatbots/{chatbotId}/webhooks/{id}Delete a webhook.
{
"message": "Webhook deleted successfully"
}curl -X POST https://your-domain.com/api/v1/chatbots/your-chatbot-id/webhooks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-session-token" \
-d '{
"name": "Lead Notifications",
"url": "https://yourapp.com/webhooks/leads",
"eventTypes": ["LEAD_CREATED"],
"maxRetries": 3,
"retryDelay": 1000
}'const express = require('express');
const crypto = require('crypto');
const app = express();
// Use raw body parser for webhook signature verification
app.use('/webhooks', express.raw({type: 'application/json'}));
function verifyWebhookSignature(body, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
const receivedSignature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}
app.post('/webhooks/pollybot', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const webhookSecret = process.env.POLLYBOT_WEBHOOK_SECRET;
// Verify the signature
if (!verifyWebhookSignature(req.body, signature, webhookSecret)) {
console.error('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}
// Parse the payload
const payload = JSON.parse(req.body);
// Handle different event types
switch (payload.event) {
case 'LEAD_CREATED':
handleLeadCreated(payload.data);
break;
default:
}
// Always respond with 200 to acknowledge receipt
res.status(200).send('OK');
});
function handleLeadCreated(lead) {
// Add your business logic here:
// - Send notification email
// - Create record in CRM
// - Trigger follow-up workflow
// - etc.
}
app.listen(3000, () => {
});Before deploying webhooks to production, you can test them using our built-in test endpoint that logs all incoming webhook data.
Use this endpoint to see exactly what data your webhooks will receive:
# Test webhook URL (use in your webhook settings) http://localhost:3000/api/test-webhook # Or for production https://your-domain.com/api/test-webhook
🎣 WEBHOOK TEST RECEIVED!
==========================================
⏰ Time: 2025-10-10T15:30:45.123Z
📦 Payload: {
"event": "LEAD_CREATED",
"data": {
"id": "lead_123",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"chatbotId": "bot_456"
}
}
🎯 LEAD INFORMATION:
Name: John Doe
Email: john@example.com
Phone: +1234567890
🔐 SIGNATURE INFO:
Signature: sha256=abc123...
Timestamp: 1728573045
==========================================Never trust webhook payloads without verifying the HMAC signature. This prevents malicious requests from affecting your system.
Return a 200 status code as quickly as possible. Perform heavy processing asynchronously after acknowledging the webhook.
Implement idempotency in your webhook handlers. The same event might be delivered multiple times due to retries.
Check the webhook delivery statistics in your chatbot settings to ensure webhooks are being delivered successfully.
If your webhook endpoint is down, events will be retried automatically. Consider implementing a fallback mechanism or alerting system.