Проверка вебхуков
Каждый запрос вебхука подписан, чтобы вы могли убедиться, что он действительно от Chatonio и не был изменён. Проверяйте подпись до того, как доверять содержимому.
Заголовки запроса
Chatonio-Signature: t=1751366400,v1=5257a869...e3f0
Chatonio-Webhook-Id: d5e1a220-4f77-4c33-a1b2-c3d4e5f60718
Chatonio-Event: message.created
Chatonio-Delivery-Attempt: 1
Content-Type: application/json- Chatonio-Signature —
t=<unix>,v1=<hex>.v1— этоHMAC-SHA256(secret, "<t>.<raw_body>"). - Chatonio-Webhook-Id — уникальный id доставки; используйте его как ключ идемпотентности, чтобы повторы не обрабатывались дважды.
- Chatonio-Event — тип события.
- Chatonio-Delivery-Attempt — номер попытки.
Как проверять
- Считайте сырое тело запроса (байты / строку) — не сериализуйте разобранный JSON заново, иначе подпись не совпадёт.
- Извлеките
tиv1из заголовка подписи. - Вычислите
HMAC-SHA256(signing_secret, t + "." + raw_body)и сравните сv1сравнением за постоянное время. - Отклоните запрос, если метка
tотличается от текущего времени более чем на ~5 минут (защита от повторов).
import crypto from 'node:crypto';
// Express example. Use the RAW request body, not a re-serialized object.
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(',').map((kv) => kv.split('='))
);
const t = Number(parts.t);
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
const ok = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(parts.v1)
);
const fresh = Math.abs(Date.now() / 1000 - t) < 300; // 5-min replay window
return ok && fresh;
}Доставка и надёжность
- Повторы — неудачная доставка (таймаут, ошибка соединения,
408,429или5xx) повторяется с экспоненциальной задержкой до 5 раз. Прочие ответы4xxсчитаются постоянными и не повторяются. - Идемпотентность — из-за повторов ваш эндпоинт может увидеть одно событие несколько раз; исключайте дубли по
Chatonio-Webhook-Id. - Авто-отключение — после 15 подряд неудачных доставок эндпоинт отключается, а владельцу проекта отправляется письмо. Включите его снова на странице Developer, когда эндпоинт восстановится.
- Журнал доставок — недавние попытки (статус, код ответа, ошибки) видны по каждому эндпоинту на странице Developer, хранятся 30 дней.
- Порядок — строгий порядок доставки не гарантирован; опирайтесь на метки
createdв payload, а не на порядок прихода.