Webhooks
Webhooks let Chatonio notify your server when something happens in your project — the most common use is being told when a customer sends a new message. Chatonio sends a signed POST with a JSON body to a URL you register.
You do not need an API key to use webhooks. Add and manage endpoints on your project’s Developer settings page (you can also manage them through the API).
Setting up an endpoint
- Open Project settings → Developer → Webhooks and click Add webhook.
- Enter your HTTPS URL and tick the events you want.
- Copy the signing secret shown once on creation — you need it to verify deliveries (see Verifying webhooks & reliability).
Your endpoint should respond with a 2xx status quickly. Do the real work asynchronously.
Allowlisting our IP
Every webhook delivery leaves Chatonio from one fixed address:
64.7.198.218
If your endpoint sits behind a firewall, a WAF, or an IP allowlist, add that address. It is stable, and any change will be announced here in advance.
An IP allowlist is not a substitute for checking the signature. It tells you a request arrived from our network, not that we sent it — only the
Chatonio-Signatureheader proves that. See Verifying webhooks & reliability.
Events
- message.created — a message was added to a conversation (any sender except internal notes). Filter on
data.message.sender_type == "CLIENT"for “new customer message”. - conversation.created — a new conversation was created.
- conversation.status_changed — a conversation changed status.
Payload shape
Every delivery has the same envelope: a unique id, the event type, an api_version, a created timestamp, and a data object specific to the event.
message.created
{
"id": "d5e1a220-4f77-4c33-a1b2-c3d4e5f60718",
"type": "message.created",
"api_version": "v1",
"created": "2026-07-01T10:30:00+00:00",
"data": {
"message": {
"id": "a1000000-0000-4000-8000-000000000001",
"conversation_id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
"sender_type": "CLIENT",
"content": "Where is my order?",
"is_internal_note": false,
"thread_id": null,
"created_at": "2026-07-01T10:30:00+00:00"
},
"conversation": {
"id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
"status": "NEW",
"channel_id": "9a1c5f30-2b6d-4c71-8e42-1a2b3c4d5e6f",
"channel_type": "WEB"
}
}
}conversation.created
{
"id": "d5e1a220-4f77-4c33-a1b2-c3d4e5f60719",
"type": "conversation.created",
"api_version": "v1",
"created": "2026-07-01T10:29:00+00:00",
"data": {
"conversation": {
"id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
"status": "NEW",
"subject": "",
"source": "CHANNEL",
"channel_id": "9a1c5f30-2b6d-4c71-8e42-1a2b3c4d5e6f",
"channel_type": "WEB",
"ticket_number": null,
"created_at": "2026-07-01T10:29:00+00:00"
}
}
}conversation.assigned
A conversation was assigned to an operator, or unassigned. One event covers both directions: on an unassign, operator is null. It fires however the change happened — an operator claiming it in the dashboard, automatic routing, or your own API call.
{
"id": "9a3f7c11-2b60-4d5e-8f09-1a2b3c4d5e6f",
"type": "conversation.assigned",
"api_version": "v1",
"created": "2026-07-01T10:46:00+00:00",
"data": {
"conversation": {
"id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
"status": "PROCESSING"
},
"operator": { "user_id": "7c1e5a02-9b43-4f18-8a77-2d6e0f4b9c81" }
}
}conversation.status_changed
{
"id": "d5e1a220-4f77-4c33-a1b2-c3d4e5f60720",
"type": "conversation.status_changed",
"api_version": "v1",
"created": "2026-07-01T10:45:00+00:00",
"data": {
"conversation": {
"id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
"status": "RESOLVED",
"previous_status": "PROCESSING"
}
}
}
message.createdfires for every customer, operator, AI and system message delivered in a conversation — internal operator notes are never sent to webhooks, sois_internal_noteis alwaysfalsein deliveries. Usesender_typeto keep only what you care about.