> ## Documentation Index
> Fetch the complete documentation index at: https://sitegpt.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive real-time notifications for chatbot events

Webhooks allow you to receive HTTP POST requests when specific events occur in your chatbot, enabling real-time integrations and automation.

<Note>
  Webhooks are available as an addon (\$59/mo or \$468/yr) or included in the Scale plan by default. Visit your [billing page](/navigating-your-account/billing) to enable this feature.
</Note>

## Available webhooks

<Tabs>
  <Tab title="Messages" icon="message">
    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
  </Tab>

  <Tab title="Escalation" icon="user-headset">
    Triggered when a user requests human support.

    **Use cases:**

    * Create support tickets
    * Alert support team
    * Route to appropriate agent
    * Track escalation metrics
  </Tab>

  <Tab title="Leads" icon="address-book">
    Triggered when a lead is captured through your chatbot.

    **Use cases:**

    * Add leads to CRM
    * Send welcome emails
    * Notify sales team
    * Update marketing automation
  </Tab>
</Tabs>

## Setting up webhooks

<Steps>
  <Step title="Navigate to webhook settings">
    Go to your chatbot dashboard and click **Settings** > **Webhooks**.
  </Step>

  <Step title="Enter webhook URLs">
    Add the endpoint URLs where you want to receive webhook notifications.
  </Step>

  <Step title="Set webhook tokens">
    Create secure tokens to verify webhook authenticity.
  </Step>

  <Step title="Save configuration">
    Click **Save** to activate your webhooks.
  </Step>

  <Step title="Test webhooks">
    Trigger test events to verify your endpoints receive data correctly.
  </Step>
</Steps>

## Webhook configuration

<AccordionGroup>
  <Accordion title="Messages webhook" icon="message">
    <ParamField path="Webhook URL" type="string" required>
      The endpoint where message notifications will be sent.

      Example: `https://your-server.com/webhooks/messages`
    </ParamField>

    <ParamField path="Webhook Token" type="string" required>
      A secret token sent in the `X-WEBHOOK-TOKEN` header for authentication.

      Example: `abc-messages-xyz`
    </ParamField>
  </Accordion>

  <Accordion title="Escalation webhook" icon="user-headset">
    <ParamField path="Webhook URL" type="string" required>
      The endpoint for escalation notifications.

      Example: `https://your-server.com/webhooks/escalations`
    </ParamField>

    <ParamField path="Webhook Token" type="string" required>
      Authentication token for escalation webhooks.

      Example: `abc-escalations-xyz`
    </ParamField>
  </Accordion>

  <Accordion title="Leads webhook" icon="address-book">
    <ParamField path="Webhook URL" type="string" required>
      The endpoint for lead capture notifications.

      Example: `https://your-server.com/webhooks/leads`
    </ParamField>

    <ParamField path="Webhook Token" type="string" required>
      Authentication token for lead webhooks.

      Example: `abc-leads-xyz`
    </ParamField>
  </Accordion>
</AccordionGroup>

## Webhook payloads

### Messages webhook payload

```json theme={null}
{
  "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
  }
}
```

<Note>
  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`.
</Note>

### Escalation webhook payload

```json theme={null}
{
  "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"
    }
  }
}
```

<Note>
  The `user` object can be `null` if the conversation was escalated before the user provided their contact information.
</Note>

### Leads webhook payload

```json theme={null}
{
  "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"
    }
  }
}
```

<Note>
  Custom fields configured in your lead collection settings will be included in the `leadDetails` object.
</Note>

## 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)

```javascript theme={null}
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)

```python theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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:

```javascript theme={null}
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

```bash theme={null}
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

<AccordionGroup>
  <Accordion title="Webhooks not being received" icon="circle-xmark">
    <Warning>If you're not receiving webhooks, check these items:</Warning>

    **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.
  </Accordion>

  <Accordion title="Authentication failures" icon="shield-xmark">
    <Warning>If webhooks are being rejected:</Warning>

    **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.
  </Accordion>

  <Accordion title="Timeout errors" icon="clock">
    <Warning>If webhooks are timing out:</Warning>

    **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.
  </Accordion>
</AccordionGroup>

## 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

<CardGroup cols={2}>
  <Card title="API reference" icon="code" href="/api-reference/v2/getting-started">
    Explore the SiteGPT API
  </Card>

  <Card title="Zapier integration" icon="bolt" href="/integrations/zapier">
    Use Zapier for no-code automation
  </Card>

  <Card title="SDK documentation" icon="book" href="/developers/sdk">
    Integrate with the JavaScript SDK
  </Card>

  <Card title="Human support" icon="user" href="/features/human-support">
    Set up escalation webhooks
  </Card>
</CardGroup>
