Webhooks

Webhooks let you receive real-time notifications when events happen in your chatbot. Connect to your CRM, trigger automations, or build custom integrations.

Plan requirement: Webhooks are available on Growth, Pro, and Agency plans.

Setting Up Webhooks

  1. Go to Settings → Webhooks in your dashboard
  2. Click Add Webhook
  3. Enter your webhook URL (must be HTTPS)
  4. Select which events you want to receive
  5. Click Save

Webhook Events

You can subscribe to any or all of these events:

EventDescription
conversation_startedA visitor opened the chat widget
message_receivedA visitor sent a message to the bot
bot_responseThe bot sent a response to the visitor

Payload Format

All webhook payloads are sent as JSON with the following structure:

Example: message_received event
{
  "event": "message_received",
  "timestamp": "2025-01-22T14:30:00.000Z",
  "bot_id": "cmkms0wt5000i93y1udty4dy0",
  "conversation_id": "conv_abc123xyz789",
  "data": {
    "message": "What are your business hours?",
    "visitor_id": "v_12345",
    "metadata": {
      "page_url": "https://yoursite.com/contact",
      "user_agent": "Mozilla/5.0..."
    }
  }
}
Example: bot_response event
{
  "event": "bot_response",
  "timestamp": "2025-01-22T14:30:01.234Z",
  "bot_id": "cmkms0wt5000i93y1udty4dy0",
  "conversation_id": "conv_abc123xyz789",
  "data": {
    "message": "We're open Monday through Friday, 9 AM to 6 PM Eastern Time.",
    "visitor_id": "v_12345",
    "sources_used": [
      {
        "title": "Contact Us",
        "url": "https://yoursite.com/contact"
      }
    ]
  }
}

Signature Verification

Every webhook request includes a signature header so you can verify it came from SiteAnswerAI. Always verify signatures in production to prevent spoofed requests.

Security: Your webhook signing secret is shown in Settings → Webhooks after you create a webhook. Keep it secure!

Signature Header

The signature is sent in the X-SiteAnswerAI-Signature header as an HMAC SHA-256 hash of the request body.

HTTP Headers
POST /your-webhook-endpoint HTTP/1.1
Host: yourserver.com
Content-Type: application/json
X-SiteAnswerAI-Signature: sha256=a1b2c3d4e5f6...

Verification Examples

Node.js
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-siteanswerai-signature'];
  const payload = JSON.stringify(req.body);

  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook...
  console.log('Event:', req.body.event);
  res.status(200).send('OK');
});
Python
import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

# In your webhook handler (Flask example):
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-SiteAnswerAI-Signature', '')
    payload = request.get_data()

    if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
        return 'Invalid signature', 401

    data = request.get_json()
    print(f"Event: {data['event']}")
    return 'OK', 200
PHP
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
    $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
    return hash_equals($expected, $signature);
}

// In your webhook handler:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SITEANSWERAI_SIGNATURE'] ?? '';

if (!verifyWebhookSignature($payload, $signature, WEBHOOK_SECRET)) {
    http_response_code(401);
    exit('Invalid signature');
}

$data = json_decode($payload, true);
error_log('Event: ' . $data['event']);
http_response_code(200);
echo 'OK';

Automatic Retries

If your webhook endpoint returns an error (4xx or 5xx status code) or times out, we'll automatically retry the delivery:

  • Retry 1: After 1 minute
  • Retry 2: After 5 minutes
  • Retry 3: After 30 minutes

After 3 failed attempts, the webhook is marked as failed. You can see failed deliveries in the webhook logs.

Delivery Logs

Every webhook delivery is logged so you can debug issues. Find the logs at:

  1. Go to Settings → Webhooks
  2. Click on a webhook to see its details
  3. Click View Logs

Each log entry shows the timestamp, event type, HTTP status code, and response time. You can also see the full request payload and response body for debugging.

Best Practices

  • Always verify signatures - Don't skip this in production!
  • Respond quickly - Return a 200 status within 5 seconds. Do heavy processing asynchronously.
  • Handle duplicates - Webhooks may be delivered more than once. Use the conversation_id to deduplicate.
  • Use HTTPS - We only send webhooks to secure endpoints.

Next Steps