Центр помощи
Chat API

Webhooks

Последнее обновление:

Обзор вебхуков

Вебхуки позволяют ChatLab уведомлять ваши системы в тот самый момент, когда в ваших чатботах что-то происходит. Вместо постоянного опроса Management API или экспорта данных вручную вы регистрируете HTTPS-эндпоинт, и ChatLab отправляет на него подписанный HTTP POST в реальном времени - когда посетитель оставляет лид, отправляет контактную форму, оценивает диалог, запрашивает оператора или когда выполняется действие ИИ.

Типичные сценарии использования:

  • передача новых лидов прямо в вашу CRM в секунду их получения
  • уведомление команды в Slack, когда посетитель запрашивает live chat (чат с оператором)
  • передача оценок и сводок диалогов в вашу собственную систему аналитики
  • мониторинг выполнения AI action (действий ИИ) и оповещения об ошибках

Доступность: ваш аккаунт должен включать функцию Webhooks.

Где настроить: в приложении администратора перейдите в Account settings -> Webhooks (Настройки аккаунта -> Вебхуки) рядом с разделом Management API. Вебхуки действуют на уровне аккаунта - один эндпоинт может получать события от всех ваших ботов или от одного выбранного бота.

Настройка эндпоинта

  1. Перейдите в Account settings -> Webhooks и нажмите Add endpoint (Добавить эндпоинт).
  2. Заполните форму эндпоинта:
    • Name (Название) - метка для вашего удобства, например, "CRM sync" или "Slack alerts".
    • URL - адрес HTTPS, на который ChatLab будет отправлять события через POST.
    • Events (События) - выберите типы событий, которые должен получать этот эндпоинт (см. каталог ниже). Выбирайте только то, что вам нужно: события с высоким объемом трафика, такие как ai_action.executed, могут создавать большую нагрузку.
    • Bot filter (Фильтр ботов) (необязательно) - выберите одного бота или All bots (Все боты) для всех ботов вашего аккаунта.
    • Custom form filter (Фильтр пользовательских форм) (необязательно) - перенаправляет отправки одной конкретной формы на этот эндпоинт. Это фильтрует только событие custom_form.submitted; все остальные события, на которые вы подписались (лиды, запросы на контакт, диалоги, live chat, действия ИИ), доставляются независимо от этой настройки.
  3. Отправьте форму. Secret (секрет) эндпоинта отображается ровно один раз в окне успешного создания - скопируйте его прямо сейчас и сохраните в надежном месте. Он понадобится вам для проверки подписей (см. раздел "Безопасность" ниже). Получить его в виде открытого текста позже невозможно.

У каждого эндпоинта также есть:

  • Переключатель включения/отключения - приостановка доставки без удаления эндпоинта. Отключенные эндпоинты просто отбрасывают события (они не ставятся в очередь для отправки позже).
  • Send sample event (Отправить тестовое событие) - отправляет подписанный тестовый запрос на ваш URL, чтобы вы могли проверить приемник сквозным образом. Вы можете выбрать тип события и отредактировать примеры значений перед отправкой, чтобы ваш обработчик получил реалистичные данные. Тест приходит как обычная доставка с eventType, соответствующим вашему выбору (или как webhook.test для простой проверки соединения).
  • Roll secret (Сменить секрет) - генерирует новый секрет и аннулирует старый. Используйте это, если секрет мог быть скомпрометирован. Новый секрет также показывается только один раз. Для контролируемой смены приостановите эндпоинт, обновите и скопируйте новый секрет, внесите изменения на стороне приемника, затем снова включите эндпоинт и отправьте тестовое событие. События, произошедшие во время паузы, не ставятся в очередь. Запланируйте этот перерыв перед сменой ключа.
  • Delivery log (Журнал доставок) - список последних доставок для конкретного эндпоинта с указанием времени, типа события, возвращенного вашим сервером HTTP-статуса и времени ответа. Здесь отображаются неудачные доставки и паузы механизма circuit breaker. Журнал хранится в течение 14 дней.

Структура события

Каждая доставка представляет собой HTTP POST с заголовком Content-Type: application/json. Тело всегда имеет одну и ту же базовую структуру (envelope); объект data зависит от типа события:

{
  "eventId": "9f1c1c8e-6a2b-4b9e-9d2f-3f8a1e2b4c5d",
  "eventType": "lead.created",
  "timestamp": "2026-08-13T14:22:31Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": { }
}
  • eventId - уникальный идентификатор события. Используйте его для дедупликации, если обработка на вашей стороне должна быть идемпотентной.
  • eventType - один из типов, описанных ниже; также передается в заголовке X-ChatLab-Event.
  • timestamp - время формирования структуры доставки по стандарту ISO 8601 в формате UTC.
  • botId / botName - бот, к которому относится событие.
  • conversationId / sessionId - контекст диалога, если применимо.

Каталог событий

lead.created

Срабатывает, когда посетитель отправляет свои контактные данные - через форму сбора лидов, предварительную форму Live Chat или пользовательскую форму, настроенную для сбора лидов.

{
  "eventId": "9f1c1c8e-6a2b-4b9e-9d2f-3f8a1e2b4c5d",
  "eventType": "lead.created",
  "timestamp": "2026-08-13T14:22:31Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "email": "jane.doe@example.com",
    "name": "Jane Doe",
    "phone": "+1 555 0123",
    "source": "LEAD_COLLECTION_FORM",
    "formCodeName": "lead_form",
    "formName": "Lead form",
    "fields": [
      {"name": "email", "value": "jane.doe@example.com", "type": "email"},
      {"name": "company", "value": "Acme Inc.", "type": "text"},
      {"name": "topics", "value": ["Billing", "Delivery"], "type": "multichoice"},
      {"name": "attachment", "value": "https://api.chatlab.com/aichat/customform/download?key=...&token=...", "type": "file"}
    ],
    "pageUrl": "https://acme.com/pricing"
  }
}
  • source - способ получения контактных данных: LEAD_COLLECTION_FORM (форма сбора лидов), LIVE_CHAT_FORM (предварительная форма Live Chat), CONVERSATION (ИИ получил данные в ходе диалога), ADMIN_DATA_UPDATE или UPDATE_CLIENT_CONTEXT (данные изменены на стороне ChatLab). Отправка формы связи с оператором никогда не вызывает это событие - вместо него срабатывает contact_form.submitted.
  • email, name, phone - контактные данные, сопоставленные с записью лида.
  • Когда для сбора лидов используется пользовательская форма, каждое настроенное в ней поле включается в fields в исходном порядке, а formCodeName / formName идентифицируют эту форму. В классической форме сбора лидов оба этих параметра равны null, а fields представляет собой пустой массив.
  • Каждый элемент в fields имеет структуру {name, value, type}. name - техническое имя поля, которое остается неизменным при редактировании подписи; используйте его для сопоставления полей в вашей CRM.
  • Для полей типа multichoice значение value представляет собой массив выбранных вариантов. Поля-чекбоксы передаются отдельными записями со значениями "true" / "false".
  • Для полей типа file значение value является ссылкой на скачивание загруженного файла; вебхук никогда не содержит тело самого файла.
  • pageUrl - страница, на которой находился посетитель в момент отправки формы.

contact_form.submitted

Срабатывает, когда посетитель отправляет форму связи с оператором или пользовательскую форму, предназначенную для связи с человеком.

{
  "eventId": "3a7b9c2d-1e4f-4a6b-8c0d-5e2f7a9b1c3d",
  "eventType": "contact_form.submitted",
  "timestamp": "2026-08-13T14:25:02Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "email": "jane.doe@example.com",
    "message": "I need help with my last invoice.",
    "source": "CUSTOM_FORM",
    "formCodeName": "contact_form",
    "formName": "Contact form",
    "fields": [
      {"name": "email", "value": "jane.doe@example.com", "type": "email"},
      {"name": "order_number", "value": "A-10293", "type": "text"},
      {"name": "message", "value": "I need help with my last invoice.", "type": "textarea"}
    ]
  }
}
  • email - адрес, оставленный посетителем, на который ваша служба поддержки должна отправить ответ.
  • source - значение CUSTOM_FORM, если в основе лежит пользовательская форма, или CONTACT_FORM для стандартной встроенной формы.
  • formCodeName / formName - идентификаторы пользовательской формы, на основе которой создан запрос; оба параметра равны null для встроенной формы.
  • При использовании пользовательской формы каждое настроенное в ней поле включается в массив fields (в том же формате {name, value, type}, что и в lead.created). Для встроенной формы заполняются только email и message, fields остается пустым массивом, а идентификаторы формы равны null.
  • message - сопоставленное поле сообщения или все заполненные значения, объединенные вместе, если в форме нет отдельного поля для сообщения.

custom_form.submitted

Срабатывает при каждой отправке пользовательской формы, независимо от ее назначения. Обратите внимание: формы, настроенные для сбора лидов или связи с оператором, также инициируют соответствующие события lead.created / contact_form.submitted. Подписывайтесь на один из типов событий в зависимости от того, нужен ли вам универсальный или специализированный формат данных, чтобы избежать дублирования бизнес-логики. У этих семейств событий разные ID; связка conversationId и timestamp не является надежным идентификатором конкретной отправки.

{
  "eventId": "6c1d8e3f-2a5b-4c7d-9e0f-1a4b6c8d0e2f",
  "eventType": "custom_form.submitted",
  "timestamp": "2026-08-13T14:27:45Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "formCodeName": "warranty_claim",
    "formName": "Warranty claim",
    "fields": [
      {"name": "order_number", "value": "A-10293", "type": "text"},
      {"name": "issue", "value": "Damaged on arrival", "type": "textarea"},
      {"name": "photo", "value": "https://api.chatlab.com/aichat/customform/download?key=...&token=...", "type": "file"}
    ],
    "purpose": "STANDALONE"
  }
}
  • formCodeName - постоянное системное имя формы, которое не меняется при ее переименовании; используйте его для маршрутизации отправленных данных в вашей системе. formName - отображаемое название формы, которое видят посетители.
  • fields содержит элементы того же формата {name, value, type}, что и lead.created: варианты из полей множественного выбора передаются в виде массивов, а файлы - в виде ссылок на скачивание.
  • purpose - STANDALONE, LEAD_COLLECTION или HUMAN_CONTACT, в зависимости от роли формы в настройках чат-бота.

conversation.started

Срабатывает, когда посетитель отправляет первое сообщение в новом диалоге.

{
  "eventId": "8e2f0a4b-3c6d-4e8f-a1b2-2c5d7e9f1a3b",
  "eventType": "conversation.started",
  "timestamp": "2026-08-13T14:20:11Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "firstMessage": "Do you ship to Canada?",
    "chatSource": "WIDGET",
    "byAdmin": false,
    "countryCode": "PL",
    "ipAddress": "83.12.44.7"
  }
}
  • firstMessage - точный текст первого сообщения посетителя. Значение равно null, если диалог был начат без текста сообщения.
  • chatSource - канал поступления диалога: WIDGET, WHATSAPP, MESSENGER, VOICE, VOICE_PHONE, API, BOOKING, AIRBNB или IDOBOOKING.
  • byAdmin - значение true, если диалог открыт в окне предпросмотра чат-бота внутри панели управления ChatLab, а не реальным посетителем. Используйте этот флаг, чтобы отфильтровать собственные тестовые чаты от передачи в CRM.
  • countryCode - код страны ISO, определенный по IP-адресу посетителя; null, если страну определить не удалось.
  • ipAddress - IP-адрес посетителя, зафиксированный сервером ChatLab; null, если адрес недоступен. Эти данные подпадают под действие GDPR как персональные данные - сохраняйте их только при наличии законных оснований.

conversation.rated

Срабатывает, когда посетитель ставит положительную или отрицательную оценку диалогу (см. Оценка диалога).

{
  "eventId": "1b4c6d8e-5f0a-4b2c-8d3e-4f7a9b1c3d5e",
  "eventType": "conversation.rated",
  "timestamp": "2026-08-13T14:31:09Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "rating": "POSITIVE"
  }
}
  • rating - значение POSITIVE или NEGATIVE. Сброс оценки не генерирует событие, поэтому нейтральные значения не передаются.

conversation.summarized

Срабатывает, когда ChatLab формирует саммари завершенного диалога.

{
  "eventId": "4d7e9f1a-6b2c-4d4e-9f0a-5b8c0d2e4f6a",
  "eventType": "conversation.summarized",
  "timestamp": "2026-08-13T14:45:00Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "summary": "Visitor asked about shipping to Canada and delivery times. The bot confirmed availability and quoted 5-7 business days. Visitor left satisfied.",
    "language": "en_US"
  }
}
  • summary - сгенерированный текст саммари. Генерация выполняется асинхронно и зависит от настроек саммари у бота и очереди обработки; не рассчитывайте на фиксированное время доставки.
  • language - внутренняя локаль бота, переданная для формирования саммари (например, en_US); этот параметр может отличаться от языка, на котором общался посетитель.

client.summarized

Срабатывает, когда ChatLab обновляет ИИ-профиль клиента. Профиль формируется заново на базе предыдущего профиля и саммари только что завершенного диалога, поэтому событие может приходить позже conversation.summarized. Порядок доставки не гарантируется. Пейлоад содержит email, если он известен, однако в базе ChatLab могут быть клиенты и без email-адреса.

{
  "eventId": "b5d8f1a3-7c2e-4d9b-a6f0-1e3c5a7b9d2f",
  "eventType": "client.summarized",
  "timestamp": "2026-08-18T09:12:04Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "clientEmail": "jane.doe@example.com",
    "client": {
      "email": "jane.doe@example.com",
      "name": "Jane Doe",
      "phone": "+1 555 0123",
      "countryCode": "PL",
      "ipAddress": "83.12.44.7"
    },
    "clientSummary": "Returning customer interested in international shipping. Asked about delivery times to Canada twice and about return costs once."
  }
}
  • clientEmail - идентификатор для сопоставления клиента с вашей CRM. Он равен null для анонимных посетителей, не оставивших адрес (для них событие тоже срабатывает) - пропускайте такие вебхуки, если в вашей интеграции ключом является e-mail.
  • client - контактные данные, зафиксированные для данного пользователя в ChatLab: email, name, phone, countryCode и ipAddress. Все ключи присутствуют всегда; неизвестные значения равны null.
  • clientSummary - полный текст профиля в виде обычного текста (не diff). Он полностью заменяет предыдущее саммари, поэтому сохраняйте его с перезаписью, а не добавляйте в конец.
  • Профиль пересчитывается только для ботов со включенной функцией памяти чата и только для тех диалогов, пауза в которых была достаточной для создания саммари. Это событие приходит не моментально, а через несколько минут после завершения диалога.

live_chat.requested

Срабатывает, когда ИИ передает диалог в Live Chat - либо по запросу посетителя, либо по решению бота о необходимости привлечь человека.

{
  "eventId": "7a0b2c4d-8e3f-4a5b-b0c1-6d9e1f3a5b7c",
  "eventType": "live_chat.requested",
  "timestamp": "2026-08-13T14:33:20Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "requestedBy": "AI"
  }
}
  • requestedBy - в настоящее время всегда AI, поскольку передача диалога всегда инициируется действием бота, даже если посетитель запросил оператора текстом. Рекомендуется обрабатывать это поле как открытый enum: предусмотрите поведение для неизвестных значений, не ограничиваясь проверкой на равенство AI.
  • Это событие фиксирует сам факт запуска действия по передаче диалога со стороны ИИ, а не любой возможный вход в live chat. Оно не гарантирует, что оператор уже подключился.

live_chat.started

Срабатывает, когда сессия live chat создана после отправки посетителем формы перевода на оператора. Это происходит еще до того, как оператор обязательно подключится или ответит; не считайте это подтверждением реального участия человека.

{
  "eventId": "0c3d5e7f-9a4b-4c6d-a1b2-7e0f2a4b6c8d",
  "eventType": "live_chat.started",
  "timestamp": "2026-08-13T14:33:55Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {}
}
  • Объект data намеренно оставлен пустым. Все необходимые сведения находятся в заголовке события: botId идентифицирует чат-бота, а conversationId / sessionId связывают событие с конкретным диалогом. Вы можете получить это событие без предварительного live_chat.requested - например, если посетитель воспользовался кнопкой вызова live chat в самом виджете.

live_chat.ended

Срабатывает при завершении сессии live chat.

{
  "eventId": "2e5f7a9b-0c5d-4e7f-b2c3-8f1a3b5c7d9e",
  "eventType": "live_chat.ended",
  "timestamp": "2026-08-13T14:52:41Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "durationSeconds": 1126
  }
}
  • durationSeconds - длительность сессии live chat в секундах, отсчитываемая от момента создания сессии, включая время ожидания оператора. В редких ситуациях, когда сессия закрылась, так и не начавшись, это поле опускается.

ai_action.executed

Срабатывает каждый раз, когда бот выполняет действие ИИ - вызов встроенной интеграции или пользовательскую функцию API. Это высоконагруженное событие: активный e-commerce бот может совершать сотни действий в день, а одна реплика посетителя может вызвать сразу несколько действий подряд. Настройте для него отдельный эндпоинт или убедитесь, что ваш сервер справится с таким объемом запросов.

{
  "eventId": "5f8a0b2c-1d6e-4f8a-c3d4-9a2b4c6d8e0f",
  "eventType": "ai_action.executed",
  "timestamp": "2026-08-13T14:21:03Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "actionName": "search_products",
    "status": "SUCCESS",
    "durationMs": 842,
    "errorMessage": null
  }
}
  • actionName - имя выполненного действия так, как его видит ИИ: например, search_products для готовой интеграции или заданное вами имя для пользовательского действия API.
  • status - значение SUCCESS или ERROR.
  • durationMs - время выполнения действия в миллисекундах. Удобно для выявления медленных интеграций до того, как на них начнут жаловаться посетители.
  • errorMessage - причина ошибки; заполняется только при статусе ERROR, во всех остальных случаях имеет значение null.

webhook.test

Отправляется по нажатию кнопки Send sample event (Отправить тестовое событие) при базовой проверке связи. Подписывается точно так же, как и реальные события.

{
  "eventId": "9b2c4d6e-3f8a-4b0c-d5e6-0b3c5d7e9f1a",
  "eventType": "webhook.test",
  "timestamp": "2026-08-13T14:10:00Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "message": "Test delivery from ChatLab"
  }
}
  • message - постоянный текст сообщения, неизменный во всех тестовых доставках. Поля заголовка содержат демонстрационные значения, поэтому никогда не обрабатывайте вебхук webhook.test как реальные боевые данные.
  • Это единственный тип события, на который нельзя подписаться вручную в настройках эндпоинта: он отправляется по запросу из панели управления и доставляется строго на тот адрес, для которого была нажата кнопка, независимо от списка выбранных событий.

Безопасность: проверка подлинности доставки

Каждый входящий запрос содержит четыре HTTP-заголовка:

Заголовок Значение
X-ChatLab-Signature sha256=<hex hmac> - подпись HMAC-SHA256 для тела запроса
X-ChatLab-Timestamp Время формирования подписи в формате Unix time (в секундах)
X-ChatLab-Event Тип события, например lead.created
X-ChatLab-Delivery Уникальный ID доставки, совпадающий со значением eventId в теле запроса

Подпись рассчитывается как HMAC-SHA256 от строки {timestamp}.{rawBody} с использованием секретного ключа вашего эндпоинта, где {timestamp} - значение заголовка X-ChatLab-Timestamp, а {rawBody} - исходное, нераспарсенное тело запроса. Всегда проверяйте подпись по исходным байтам - повторная сериализация распарсенного JSON изменит последовательность байтов и сделает подпись недействительной.

Для защиты от атак повторного воспроизведения (replay attacks) отклоняйте запросы, значение X-ChatLab-Timestamp в которых отличается от текущего времени более чем на 5 минут.

Node.js

const crypto = require('crypto');

function verifyChatLabSignature(req, secret) {
    const signature = req.headers['x-chatlab-signature'];
    const timestamp = req.headers['x-chatlab-timestamp'];
    if (typeof signature !== 'string' || typeof timestamp !== 'string') return false;
    if (!/^\d+$/.test(timestamp) || !Number.isSafeInteger(Number(timestamp))) return false;
    if (!Buffer.isBuffer(req.rawBody)) return false;

    // Reject stale deliveries (older than 5 minutes)
    const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
    if (ageSeconds > 300) return false;

    // rawBody must be the raw request body bytes, not re-serialized JSON.
    // With Express: app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }))
    const expected = 'sha256=' + crypto
        .createHmac('sha256', secret)
        .update(timestamp + '.')
        .update(req.rawBody)
        .digest('hex');

    const a = Buffer.from(signature);
    const b = Buffer.from(expected);
    return a.length === b.length && crypto.timingSafeEqual(a, b);
}

PHP

<?php
function verifyChatLabSignature(string $secret): bool
{
    $signature = $_SERVER['HTTP_X_CHATLAB_SIGNATURE'] ?? '';
    $timestamp = $_SERVER['HTTP_X_CHATLAB_TIMESTAMP'] ?? '';
    if ($signature === '' || $timestamp === '' || !ctype_digit($timestamp)) {
        return false;
    }

    // Reject stale deliveries (older than 5 minutes)
    if (abs(time() - (int) $timestamp) > 300) {
        return false;
    }

    $rawBody = file_get_contents('php://input');
    $expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);

    return hash_equals($expected, $signature);
}

Если проверка не пройдена, верните ответ со статусом 401 и отклоните полученные данные. Никогда не обрабатывайте неподтвержденные запросы: любой, кто узнает адрес вашего эндпоинта, сможет отправлять на него произвольные данные JSON.

Поведение доставки

Ознакомьтесь с этими правилами доставки, прежде чем приступать к разработке на базе webhook:

  • Отвечайте быстро. Ваш эндпоинт должен ответить в течение 3 секунд, иначе попытка доставки будет считаться неудачной. Проверьте подпись, надежно поставьте событие в очередь и верните статус 2xx в пределах этого интервала. Более медленные вызовы CRM и бизнес-логику выполняйте асинхронно.
  • Fire-and-forget, не более одного раза. Подходящие включенные эндпоинты получают не более одной попытки доставки - повторных попыток нет. Приостановленные эндпоинты и разомкнутые цепи могут отменить даже эту попытку. Если ваш эндпоинт недоступен, превышает таймаут или возвращает статус, отличный от 2xx, событие теряется и не будет отправлено повторно. Webhook - это уведомления, а не реплицированное хранилище данных: используйте эндпоинты диалогов Bot Talk API или экспорт лидов для синхронизации сохраненных данных там, где это поддерживается. Management API охватывает настройки ботов и данные об использовании, но не полный архив событий. Некоторые события невозможно восстановить через эти интерфейсы.
  • Автоматический выключатель (circuit breaker). После 5 неудачных доставок подряд для пары эндпоинт/бот доставки для этой пары приостанавливаются на 5 минут. События, происходящие во время паузы, отбрасываются, а в журнале доставок появляются записи CIRCUIT_OPEN для обозначения отмененных попыток. Доставки, пропущенные из-за разомкнутой цепи, не учитываются при автоматическом отключении.
  • Автоматическое отключение. Проверка выполняется в момент неудачной доставки, а не по расписанию. Если доставка не удалась и в течение 7 дней не было ни одной успешной доставки - отсчет ведется от последнего успеха или от даты создания эндпоинта, если успешных доставок не было вовсе - эндпоинт отключается, а вы получаете уведомление по электронной почте. Любой статус 2xx в любой момент сбрасывает этот таймер. Эндпоинт, который не получает трафик, никогда не отключается, поскольку в нем нет сбоев. Включите его снова в Account settings (настройки аккаунта), когда исправите свой приемник; счетчик сбоев и отметка автоотключения сбрасываются при повторном включении, а события, пропущенные во время отключения, задним числом не отправляются.
  • 410 Gone. Если ваш эндпоинт отвечает с HTTP-статусом 410 Gone, ChatLab немедленно отключает его. Используйте это для программного вывода эндпоинта из эксплуатации на стороне приемника.
  • Идемпотентность. В штатном режиме дублирование доставок не ожидается, но если ваша обработка требует строгой идемпотентности, выполняйте дедупликацию по eventId (также доступен в заголовке X-ChatLab-Delivery).

Порядок доставки не гарантируется. Сохраняйте идентификатор события и делайте бизнес-обработку идемпотентной. Самостоятельно настраивайте сроки хранения и права доступа для полезных нагрузок webhook, так как они могут содержать персональные данные и ссылки на скачивание файлов.

В примерах подписи используются Node.js crypto и функция hash_equals в PHP. Получайте необработанное тело запроса (raw body) до его парсинга.

Лимиты

  • До 10 webhook-эндпоинтов на аккаунт.
  • Срок хранения журнала доставок: 14 дней. Более старые записи удаляются автоматически.

Связанные статьи