Skip to main content
Webhooks allow you to receive HTTP POST requests when specific events occur in your chatbot, enabling real-time integrations and automation.
Webhooks are available as an addon (59/moor59/mo or 468/yr) or included in the Scale plan by default. Visit your billing page to enable this feature.

Available webhooks

  • Messages
  • Escalation
  • Leads
Triggered when your chatbot sends a message to a user.Use cases:
  • Log conversations to your database
  • Analyze chatbot performance
  • Trigger custom workflows
  • Monitor chatbot activity

Setting up webhooks

1

Navigate to webhook settings

Go to your chatbot dashboard and click Settings > Webhooks.
2

Enter webhook URLs

Add the endpoint URLs where you want to receive webhook notifications.
3

Set webhook tokens

Create secure tokens to verify webhook authenticity.
4

Save configuration

Click Save to activate your webhooks.
5

Test webhooks

Trigger test events to verify your endpoints receive data correctly.

Webhook configuration

Webhook URL
string
required
The endpoint where message notifications will be sent.Example: https://your-server.com/webhooks/messages
Webhook Token
string
required
A secret token sent in the X-WEBHOOK-TOKEN header for authentication.Example: abc-messages-xyz
Webhook URL
string
required
The endpoint for escalation notifications.Example: https://your-server.com/webhooks/escalations
Webhook Token
string
required
Authentication token for escalation webhooks.Example: abc-escalations-xyz
Webhook URL
string
required
The endpoint for lead capture notifications.Example: https://your-server.com/webhooks/leads
Webhook Token
string
required
Authentication token for lead webhooks.Example: abc-leads-xyz

Webhook payloads

Messages webhook payload

{
  "event": "ADD_MESSAGE",
  "data": {
    "chatbotId": "chatbot_123",
    "threadId": "thread_456",
    "gptModel": "gpt-3.5-turbo",
    "sources": ["https://example.com/docs/page1", "https://example.com/docs/page2"],
    "question": "How do I reset my password?",
    "answer": "To reset your password, click on 'Forgot Password' on the login page.",
    "messageType": "NORMAL_MESSAGE",
    "agentId": null,
    "iconUrl": null,
    "agentName": null,
    "systemMessageType": null
  }
}
The question and answer fields can be null depending on the message type. For user messages, answer will be null. For agent messages, question will be null.

Escalation webhook payload

{
  "event": "CONVERSATION_ESCALATED",
  "data": {
    "chatbotId": "chatbot_123",
    "threadId": "thread_456",
    "dashboardUrl": "https://sitegpt.ai/chatbot_123/chat-history/thread_456",
    "user": {
      "id": "user_321",
      "email": "user@example.com",
      "name": "John Doe",
      "phone": "+1234567890",
      "verified": true,
      "createdAt": "2024-01-15T10:25:00Z"
    }
  }
}
The user object can be null if the conversation was escalated before the user provided their contact information.

Leads webhook payload

{
  "event": "NEW_LEAD_CAPTURE",
  "data": {
    "chatbotId": "chatbot_123",
    "chatbotName": "Support Bot",
    "dashboardUrl": "https://sitegpt.ai/chatbot_123/leads/lead_789",
    "leadDetails": {
      "id": "lead_789",
      "name": "John Doe",
      "email": "john@example.com",
      "phone": "+1234567890",
      "capturedAt": "2024-01-15T10:30:00Z"
    }
  }
}
Custom fields configured in your lead collection settings will be included in the leadDetails object.

Implementing webhook endpoints

Basic endpoint structure

Your webhook endpoint should:
  1. Accept POST requests
  2. Verify the webhook token
  3. Process the payload
  4. Return a 200 status code quickly
  5. Handle errors gracefully

Example implementation (Node.js)

const express = require('express');
const app = express();

app.use(express.json());

// Messages webhook endpoint
app.post('/webhooks/messages', (req, res) => {
  // Verify webhook token
  const token = req.headers['x-webhook-token'];
  if (token !== process.env.SITEGPT_MESSAGE_TOKEN) {
    return res.status(401).send('Unauthorized');
  }

  // Process the webhook payload
  const { event, data } = req.body;
  
  if (event === 'ADD_MESSAGE') {
    console.log(`New message in thread ${data.threadId}`);
    console.log(`Question: ${data.question}`);
    console.log(`Answer: ${data.answer}`);
  }
  
  // Your custom logic here
  // - Log to database
  // - Trigger notifications
  // - Update analytics
  
  // Respond quickly
  res.status(200).send('OK');
});

// Escalation webhook endpoint
app.post('/webhooks/escalations', (req, res) => {
  const token = req.headers['x-webhook-token'];
  if (token !== process.env.SITEGPT_ESCALATION_TOKEN) {
    return res.status(401).send('Unauthorized');
  }

  const { event, data } = req.body;
  
  if (event === 'CONVERSATION_ESCALATED') {
    console.log(`Escalation from ${data.user?.name || 'Anonymous'}`);
    console.log(`Dashboard URL: ${data.dashboardUrl}`);
  }
  
  // Your custom logic here
  // - Create support ticket
  // - Notify support team
  // - Send confirmation email
  
  res.status(200).send('OK');
});

// Leads webhook endpoint
app.post('/webhooks/leads', (req, res) => {
  const token = req.headers['x-webhook-token'];
  if (token !== process.env.SITEGPT_LEADS_TOKEN) {
    return res.status(401).send('Unauthorized');
  }

  const { event, data } = req.body;
  
  if (event === 'NEW_LEAD_CAPTURE') {
    console.log(`New lead: ${data.leadDetails.name} (${data.leadDetails.email})`);
    console.log(`Dashboard URL: ${data.dashboardUrl}`);
  }
  
  // Your custom logic here
  // - Add to CRM
  // - Send welcome email
  // - Notify sales team
  
  res.status(200).send('OK');
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

Example implementation (Python)

from flask import Flask, request, jsonify
import os

app = Flask(__name__)

@app.route('/webhooks/messages', methods=['POST'])
def messages_webhook():
    # Verify webhook token
    token = request.headers.get('X-WEBHOOK-TOKEN')
    if token != os.environ.get('SITEGPT_MESSAGE_TOKEN'):
        return 'Unauthorized', 401
    
    # Process the webhook payload
    payload = request.json
    event = payload.get('event')
    data = payload.get('data')
    
    if event == 'ADD_MESSAGE':
        print(f"New message in thread {data['threadId']}")
        print(f"Question: {data.get('question')}")
        print(f"Answer: {data.get('answer')}")
    
    # Your custom logic here
    
    return 'OK', 200

@app.route('/webhooks/escalations', methods=['POST'])
def escalations_webhook():
    token = request.headers.get('X-WEBHOOK-TOKEN')
    if token != os.environ.get('SITEGPT_ESCALATION_TOKEN'):
        return 'Unauthorized', 401
    
    payload = request.json
    event = payload.get('event')
    data = payload.get('data')
    
    if event == 'CONVERSATION_ESCALATED':
        user = data.get('user')
        user_name = user['name'] if user else 'Anonymous'
        print(f"Escalation from {user_name}")
        print(f"Dashboard URL: {data['dashboardUrl']}")
    
    # Your custom logic here
    
    return 'OK', 200

@app.route('/webhooks/leads', methods=['POST'])
def leads_webhook():
    token = request.headers.get('X-WEBHOOK-TOKEN')
    if token != os.environ.get('SITEGPT_LEADS_TOKEN'):
        return 'Unauthorized', 401
    
    payload = request.json
    event = payload.get('event')
    data = payload.get('data')
    
    if event == 'NEW_LEAD_CAPTURE':
        lead = data['leadDetails']
        print(f"New lead: {lead['name']} ({lead['email']})")
        print(f"Dashboard URL: {data['dashboardUrl']}")
    
    # Your custom logic here
    
    return 'OK', 200

if __name__ == '__main__':
    app.run(port=3000)

Security best practices

Verify webhook tokens

Always verify the X-WEBHOOK-TOKEN header matches your configured token:
if (req.headers['x-webhook-token'] !== expectedToken) {
  return res.status(401).send('Unauthorized');
}

Use HTTPS

Always use HTTPS endpoints to encrypt webhook data in transit.

Validate payloads

Validate the structure and content of webhook payloads before processing:
if (!payload.event || !payload.chatbotId) {
  return res.status(400).send('Invalid payload');
}

Handle errors gracefully

Implement error handling to prevent webhook failures from breaking your application:
try {
  await processWebhook(payload);
  res.status(200).send('OK');
} catch (error) {
  console.error('Webhook processing error:', error);
  res.status(500).send('Internal server error');
}

Respond quickly

Return a 200 status code within 5 seconds. Process time-consuming tasks asynchronously:
app.post('/webhooks/messages', async (req, res) => {
  // Respond immediately
  res.status(200).send('OK');
  
  // Process asynchronously
  processWebhookAsync(req.body).catch(console.error);
});

Testing webhooks

Use webhook testing tools

Test your endpoints with tools like:
  • Webhook.site - Inspect webhook payloads
  • ngrok - Expose local servers for testing
  • Postman - Send test webhook requests
  • curl - Command-line testing

Test with curl

curl -X POST https://your-server.com/webhooks/messages \
  -H "Content-Type: application/json" \
  -H "X-WEBHOOK-TOKEN: your-token" \
  -d '{
    "event": "ADD_MESSAGE",
    "data": {
      "chatbotId": "test_123",
      "threadId": "test_thread",
      "question": "Test question",
      "answer": "Test answer",
      "messageType": "NORMAL_MESSAGE"
    }
  }'

Monitor webhook delivery

Check your server logs to verify:
  • Webhooks are being received
  • Tokens are validated correctly
  • Payloads are processed successfully
  • Responses are sent promptly

Troubleshooting

If you’re not receiving webhooks, check these items:
Verify endpoint URL
Ensure the URL is correct and publicly accessible.
Check HTTPS
Webhooks only work with HTTPS endpoints (except localhost for testing).
Test connectivity
Use curl or Postman to verify your endpoint responds to POST requests.
Review firewall rules
Ensure your server allows incoming connections from SiteGPT.
If webhooks are being rejected:
Verify token
Ensure the token in your code matches the one configured in SiteGPT.
Check header name
The token is sent in the X-WEBHOOK-TOKEN header (case-sensitive).
Review logs
Check your server logs for authentication errors.
If webhooks are timing out:
Respond quickly
Return a 200 status within 5 seconds.
Process asynchronously
Move time-consuming tasks to background jobs.
Optimize code
Profile your webhook handler for performance bottlenecks.

Webhook retries

SiteGPT automatically retries failed webhooks:
  • Retry attempts: Up to 3 times
  • Retry delay: Exponential backoff (1s, 5s, 25s)
  • Failure conditions: Non-200 status codes or timeouts
After 3 failed attempts, the webhook is marked as failed and no further retries occur.

Next steps

I