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 / m o o r 59/mo or 59/ m oor 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
Navigate to webhook settings
Go to your chatbot dashboard and click Settings > Webhooks .
Enter webhook URLs
Add the endpoint URLs where you want to receive webhook notifications.
Set webhook tokens
Create secure tokens to verify webhook authenticity.
Save configuration
Click Save to activate your webhooks.
Test webhooks
Trigger test events to verify your endpoints receive data correctly.
Webhook configuration
The endpoint where message notifications will be sent. Example: https://your-server.com/webhooks/messages
A secret token sent in the X-WEBHOOK-TOKEN
header for authentication. Example: abc-messages-xyz
The endpoint for escalation notifications. Example: https://your-server.com/webhooks/escalations
Authentication token for escalation webhooks. Example: abc-escalations-xyz
The endpoint for lead capture notifications. Example: https://your-server.com/webhooks/leads
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:
Accept POST requests
Verify the webhook token
Process the payload
Return a 200 status code quickly
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
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
Webhooks not being received
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