Webhooks
Webhooks let you receive real-time notifications when events happen in your chat widget. When a visitor starts a chat, submits a form, or sends a message, Chatim sends an HTTP POST request to your URL with the event data.
Overview
With webhooks you can:
- Send new leads to your CRM automatically
- Trigger workflows in Zapier, Make, or custom apps
- Log chat events to your analytics platform
- Notify your team in Slack or other tools
- Sync visitor data with your database
Accessing Webhooks
- Log in to your Chatim dashboard
- Select your project from the sidebar
- Click Webhooks in the navigation menu
Creating a Webhook
- Click Create Webhook
- Enter an optional Name (e.g., "CRM Integration")
- Enter the URL where events should be sent
- Select one or more Events you want to receive
- Click Create
After creation, you'll see a Webhook Secret - copy and save it immediately. This secret is used to verify that incoming requests are from Chatim. It is only shown once.
Supported Events
| Event | Triggered When |
|---|---|
chat.started | A visitor opens the chat widget and begins a new session |
chat.message.received | A visitor sends a text message |
chat.form.submitted | A visitor submits a form in the chatbot flow |
chat.closed | A chat session is closed |
chat.assigned | A support agent joins the conversation |
chat.handoff | The chatbot transitions from bot mode to live chat |
Webhook Payload
Every webhook delivery is an HTTP POST request with a JSON body.
Common Fields
{
"event": "chat.started",
"eventId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2025-01-15T10:30:00.000Z",
"projectUuid": "your-project-uuid",
"chatUuid": "visitor-chat-uuid",
"data": { }
}chat.started
Includes visitor info, page URL, location, and user agent.
{
"event": "chat.started",
"data": {
"visitor": {
"uuid": "visitor-uuid",
"name": "John Doe",
"email": "[email protected]",
"phone": "+1234567890"
},
"page": {
"url": "https://example.com/pricing",
"title": "Pricing - Example"
},
"location": { "country": "US", "city": "Los Angeles" },
"userAgent": { "browser": "Chrome", "os": "Windows", "device": "Desktop" }
}
}chat.message.received
{
"event": "chat.message.received",
"data": {
"messageUuid": "message-uuid",
"message": "Hi, I have a question about your pricing.",
"visitor": { "uuid": "visitor-uuid", "name": "John Doe" }
}
}chat.form.submitted
{
"event": "chat.form.submitted",
"data": {
"formNodeId": "node-id",
"formName": "Contact Form",
"fields": {
"name": "John Doe",
"email": "[email protected]",
"phone": "+1234567890",
"message": "I'd like a product demo."
},
"visitor": { "uuid": "visitor-uuid", "name": "John Doe" }
}
}chat.closed
Includes who closed the chat (agent, visitor, system, or timeout), duration in seconds, message count, and transcript.
{
"event": "chat.closed",
"data": {
"closedBy": "agent",
"status": "closed",
"duration": 345,
"messageCount": 12,
"visitor": { "uuid": "visitor-uuid", "name": "John Doe" }
}
}chat.assigned
Sent when a support agent joins the conversation.
{
"event": "chat.assigned",
"data": {
"assignedTo": { "uuid": "agent-uuid", "name": "Jane Smith" },
"visitor": { "uuid": "visitor-uuid", "name": "John Doe" }
}
}chat.handoff
Sent when the chatbot transitions to live chat mode.
{
"event": "chat.handoff",
"data": {
"reason": "Visitor requested human support",
"fromNode": "node-id",
"visitor": { "uuid": "visitor-uuid", "name": "John Doe" }
}
}Security
Signature Verification
Every webhook request includes a signature so you can verify it came from Chatim. The signature is computed as HMAC-SHA256(secret, timestamp + "." + payload) and sent in the X-Chatim-Signature header.
Request Headers
| Header | Description |
|---|---|
X-Chatim-Signature | HMAC-SHA256 signature of the payload |
X-Chatim-Timestamp | Unix timestamp of when the request was sent |
X-Chatim-Event | The event type |
X-Chatim-Delivery-Id | Unique delivery identifier |
Node.js Verification Example
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-chatim-signature'];
const timestamp = req.headers['x-chatim-timestamp'];
const body = JSON.stringify(req.body);
// Reject requests older than 5 minutes
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
if (age > 300) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Python Verification Example
import hmac, hashlib, time
def verify_webhook(headers, body, secret):
signature = headers.get('X-Chatim-Signature', '')
timestamp = headers.get('X-Chatim-Timestamp', '')
if abs(time.time() - int(timestamp)) > 300:
return False
expected = 'sha256=' + hmac.new(
secret.encode(),
f'{timestamp}.{body}'.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Retry Logic
If your endpoint is unavailable or returns an error, Chatim automatically retries.
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 24 hours |
After 5 failed retries, the delivery is marked as failed. 2xx responses are treated as success, 4xx as permanent failures (no retry), 5xx and timeouts (30s) trigger retries.
If a webhook accumulates 10 consecutive failures, it is automatically disabled. You can re-enable it from the dashboard after fixing the issue.
Managing Webhooks
Testing
Click Test on any webhook to send a sample chat.started event to your URL. This lets you verify your endpoint before going live.
Delivery History
Click on a webhook to view recent deliveries with event type, timestamp, HTTP status code, and error messages. History is retained for 30 days.
Regenerating a Secret
If your webhook secret is compromised, click Regenerate Secret, save the new secret, and update your endpoint. The old secret is immediately invalidated.
Use Cases
CRM Integration
Subscribe to chat.form.submitted and chat.started to automatically create contacts and leads in your CRM.
Slack Notifications
Subscribe to chat.assigned and chat.handoff to alert your team when a visitor needs live support.
Analytics
Subscribe to all events to build a complete picture of chat engagement, form conversion rates, and support response times.
Email Automation
Subscribe to chat.form.submitted to trigger welcome emails, follow-up sequences, or confirmation messages.
Best Practices
- Return a 2xx response quickly - process data asynchronously
- Use HTTPS for your endpoint URL
- Always verify the webhook signature before processing
- Implement idempotency using the
eventIdto handle duplicate deliveries - Store your webhook secret securely (environment variable, secrets manager)
- Validate the timestamp to prevent replay attacks (reject requests older than 5 minutes)
Troubleshooting
Webhook Not Receiving Events
- Check that the webhook is Active (not disabled)
- Verify the URL is correct and publicly accessible
- Use the Test button to send a sample event
- Check your server logs for incoming requests
- Ensure your endpoint returns a 2xx status code
Webhook Auto-Disabled
- Check the disabled reason in the dashboard
- Fix the underlying issue (endpoint down, returning errors)
- Click Enable to reactivate
- Use Test to verify before re-enabling
Signature Verification Failing
- Ensure you're using the correct secret
- Verify you're signing
timestamp + "." + raw_body(not parsed JSON) - Use timing-safe comparison to prevent timing attacks