curl --request POST \
--url https://your-instance.example.com/api/webhook/webchat \
--header 'Content-Type: application/json' \
--data '
{
"webchatId": "wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01",
"webchatConfigId": "5f7b1c2e8a1d4e0012c3b4a5",
"message": "Hi, do you ship to Canada?",
"deviceId": "dev_4f9a-8c1b-2e3d-7a01",
"visitorName": "Alex Morgan",
"visitorEmail": "alex@example.com",
"visitorPhone": "+14165550100",
"metadata": {
"page": "/pricing",
"referrer": "https://google.com"
}
}
'import requests
url = "https://your-instance.example.com/api/webhook/webchat"
payload = {
"webchatId": "wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01",
"webchatConfigId": "5f7b1c2e8a1d4e0012c3b4a5",
"message": "Hi, do you ship to Canada?",
"deviceId": "dev_4f9a-8c1b-2e3d-7a01",
"visitorName": "Alex Morgan",
"visitorEmail": "alex@example.com",
"visitorPhone": "+14165550100",
"metadata": {
"page": "/pricing",
"referrer": "https://google.com"
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
webchatId: 'wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01',
webchatConfigId: '5f7b1c2e8a1d4e0012c3b4a5',
message: 'Hi, do you ship to Canada?',
deviceId: 'dev_4f9a-8c1b-2e3d-7a01',
visitorName: 'Alex Morgan',
visitorEmail: 'alex@example.com',
visitorPhone: '+14165550100',
metadata: {page: '/pricing', referrer: 'https://google.com'}
})
};
fetch('https://your-instance.example.com/api/webhook/webchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://your-instance.example.com/api/webhook/webchat",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'webchatId' => 'wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01',
'webchatConfigId' => '5f7b1c2e8a1d4e0012c3b4a5',
'message' => 'Hi, do you ship to Canada?',
'deviceId' => 'dev_4f9a-8c1b-2e3d-7a01',
'visitorName' => 'Alex Morgan',
'visitorEmail' => 'alex@example.com',
'visitorPhone' => '+14165550100',
'metadata' => [
'page' => '/pricing',
'referrer' => 'https://google.com'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.example.com/api/webhook/webchat"
payload := strings.NewReader("{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://your-instance.example.com/api/webhook/webchat")
.header("Content-Type", "application/json")
.body("{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://your-instance.example.com/api/webhook/webchat")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "Webchat webhook received"
}{
"error": "Webhook processing failed"
}{
"error": "Webhook processing failed"
}Handle inbound webchat message
Inbound webhook called by the embedded webchat widget when a visitor sends a message. Validates the configured webchatConfigId, upserts the visitor as a contact, persists the message + any attachments, and emits a socket event so connected agents can respond.
curl --request POST \
--url https://your-instance.example.com/api/webhook/webchat \
--header 'Content-Type: application/json' \
--data '
{
"webchatId": "wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01",
"webchatConfigId": "5f7b1c2e8a1d4e0012c3b4a5",
"message": "Hi, do you ship to Canada?",
"deviceId": "dev_4f9a-8c1b-2e3d-7a01",
"visitorName": "Alex Morgan",
"visitorEmail": "alex@example.com",
"visitorPhone": "+14165550100",
"metadata": {
"page": "/pricing",
"referrer": "https://google.com"
}
}
'import requests
url = "https://your-instance.example.com/api/webhook/webchat"
payload = {
"webchatId": "wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01",
"webchatConfigId": "5f7b1c2e8a1d4e0012c3b4a5",
"message": "Hi, do you ship to Canada?",
"deviceId": "dev_4f9a-8c1b-2e3d-7a01",
"visitorName": "Alex Morgan",
"visitorEmail": "alex@example.com",
"visitorPhone": "+14165550100",
"metadata": {
"page": "/pricing",
"referrer": "https://google.com"
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
webchatId: 'wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01',
webchatConfigId: '5f7b1c2e8a1d4e0012c3b4a5',
message: 'Hi, do you ship to Canada?',
deviceId: 'dev_4f9a-8c1b-2e3d-7a01',
visitorName: 'Alex Morgan',
visitorEmail: 'alex@example.com',
visitorPhone: '+14165550100',
metadata: {page: '/pricing', referrer: 'https://google.com'}
})
};
fetch('https://your-instance.example.com/api/webhook/webchat', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://your-instance.example.com/api/webhook/webchat",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'webchatId' => 'wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01',
'webchatConfigId' => '5f7b1c2e8a1d4e0012c3b4a5',
'message' => 'Hi, do you ship to Canada?',
'deviceId' => 'dev_4f9a-8c1b-2e3d-7a01',
'visitorName' => 'Alex Morgan',
'visitorEmail' => 'alex@example.com',
'visitorPhone' => '+14165550100',
'metadata' => [
'page' => '/pricing',
'referrer' => 'https://google.com'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://your-instance.example.com/api/webhook/webchat"
payload := strings.NewReader("{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://your-instance.example.com/api/webhook/webchat")
.header("Content-Type", "application/json")
.body("{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://your-instance.example.com/api/webhook/webchat")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"webchatId\": \"wc_8f3d1b9c-2e7a-4f0b-9a4d-2c1e6e2f8c01\",\n \"webchatConfigId\": \"5f7b1c2e8a1d4e0012c3b4a5\",\n \"message\": \"Hi, do you ship to Canada?\",\n \"deviceId\": \"dev_4f9a-8c1b-2e3d-7a01\",\n \"visitorName\": \"Alex Morgan\",\n \"visitorEmail\": \"alex@example.com\",\n \"visitorPhone\": \"+14165550100\",\n \"metadata\": {\n \"page\": \"/pricing\",\n \"referrer\": \"https://google.com\"\n }\n}"
response = http.request(request)
puts response.read_body{
"message": "Webchat webhook received"
}{
"error": "Webhook processing failed"
}{
"error": "Webhook processing failed"
}Body
Per-conversation widget session identifier generated client-side.
WebchatConfig _id that identifies which embedded widget sent the message.
Visitor message body.
Stable per-browser device identifier used to deduplicate visitors across sessions.
Optional visitor display name captured by the widget pre-chat form.
Optional visitor email captured by the widget pre-chat form.
Optional visitor phone number captured by the widget pre-chat form.
Free-form context the widget attaches (referrer, page URL, UTM params, etc.).
Response
Message accepted (processed asynchronously)
Ack returned to the embedded webchat widget after queuing an inbound message for async processing.