for developers
Outgoing webhooks
ChatNeuron sends a POST to your system when a new lead arrives or a customer starts a conversation — no API polling needed.
Setup
- The account owner or an admin adds the URL in the dashboard: Settings → API and webhooks → Outgoing webhooks and picks the events.
https://only, no credentials in the URL. Internal network addresses are rejected.- A
whsec_…secret is shown once after you add the webhook — use it to verify signatures. Save it right away. - The “Test” button sends a
testevent; the last delivery result is shown in the list. Up to 10 webhooks per company.
Events
| event | When |
|---|---|
lead.created | A new lead from any channel or the API. Leads hidden until the plan is paid are not sent. |
dialog.started | A customer started a new conversation in any channel. Test conversations are not sent. |
test | A test delivery from settings. |
Request
JSON body { id, event, createdAt, data }. id is a unique delivery id — use it to drop duplicates. A lead.created example:
POST /hooks/chatneuron HTTP/1.1
Content-Type: application/json
User-Agent: ChatNeuron-Webhooks/1
X-ChatNeuron-Event: lead.created
X-ChatNeuron-Webhook-Id: 8d0c7c1e-…
X-ChatNeuron-Delivery-Attempt: 1
X-ChatNeuron-Signature: t=1761556502,v1=5f2b…
{
"id": "8d0c7c1e-…",
"event": "lead.created",
"createdAt": "2026-10-27T09:15:02.114Z",
"data": {
"id": "cmv…",
"agentId": "cmu…",
"name": "Анна",
"phone": "+79991234567",
"email": null,
"message": "Нужна консультация по доставке",
"type": null,
"topic": "Доставка",
"source": "chat",
"score": 72,
"createdAt": "2026-10-27T09:15:02.114Z"
}
}A dialog.started example:
{
"id": "1f4e…",
"event": "dialog.started",
"createdAt": "2026-10-27T09:12:40.003Z",
"data": {
"id": "cmv…",
"agentId": "cmu…",
"channel": "telegram",
"topic": null,
"startedAt": "2026-10-27T09:12:40.003Z"
}
}Verifying the signature
Header X-ChatNeuron-Signature: t=<unix time>,v1=<signature>. The signature is a hex HMAC-SHA256 of <t>.<raw body> keyed with the webhook secret. Compute it over the raw body, before parsing JSON, and reject requests older than 5 minutes.
Node.js
import { createHmac, timingSafeEqual } from "node:crypto"
// rawBody — тело запроса строкой, как пришло (до JSON.parse)
export function verifyChatNeuron(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")))
const t = Number(parts.t)
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
const got = Buffer.from(parts.v1 ?? "", "hex")
const want = Buffer.from(expected, "hex")
return got.length === want.length && timingSafeEqual(got, want)
}Python
import hashlib, hmac, time
def verify_chatneuron(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts.get("t", 0))
if not t or abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))Delivery
- Success is any 2xx response within 8 seconds. Respond right away and do heavy work in the background.
- Retries: if your endpoint does not answer 2xx we retry after 1, 5, 15 minutes, 1, 3, 6 and 12 hours — 8 attempts within a day. Delivery is at least once: dedupe by
id(also inX-ChatNeuron-Webhook-Id). After 3 days of failures the webhook is turned off and the owner is notified. - Redirects are not followed. Catch up on missed events with the REST API and the
sinceparameter.