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/mo or $468/yr) or included in the Scale plan by default. Visit your billing page  to enable this feature. Available webhooks 
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 payloadsngrok  - Expose local servers for testingPostman  - Send test webhook requestscurl  - 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 Check HTTPS Test connectivity Review firewall rules 
If webhooks are being rejected:
Verify token Check header name X-WEBHOOK-TOKEN header (case-sensitive).Review logs 
If webhooks are timing out:
Respond quickly Process asynchronously Optimize code Webhook retries SiteGPT automatically retries failed webhooks: 
Retry attempts : Up to 3 timesRetry 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