Войти в ЛК
Разделы документации

Документация → События и вебхуки

События и вебхуки

Уведомления о рассылках на ваш адрес и журнал для сверки.

События рассылок: вебхук на адрес ресторана и журнал GET /v1/events для сверки.

Вебхук

Адрес вебхука указывается в кабинете: Интеграции → API → Вебхук (только https). При подключении один раз показывается секрет подписи вида whsec_…. LazyCRM шлёт POST с JSON-событием; успех — любой ответ 2xx в течение 10 секунд, иначе повторы с нарастающей паузой около трёх с половиной суток. Порядок и однократность не гарантируются — обрабатывайте событие идемпотентно по его id, а после простоя приёмника сверяйтесь с журналом.

Событие тонкое: за данными идите в GET /v1/campaigns/{campaign_id}. Новый смысл события — новый type, старый не меняется.

Подпись

Подпись — по спецификации Standard Webhooks: заголовки webhook-id, webhook-timestamp, webhook-signature. Подписывается строка {webhook-id}.{webhook-timestamp}.{тело} ключом из секрета (base64 после whsec_) по HMAC-SHA256. Отклоняйте запросы старше 5 минут.

import base64, hashlib, hmac, time

def verify(secret: str, headers: dict, body: bytes) -> bool:
    msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
    if abs(time.time() - int(ts)) > 300:
        return False
    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{ts}.".encode() + body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
    return any(hmac.compare_digest("v1," + expected, s) for s in headers["webhook-signature"].split())

Объект Event

Событие рассылки — тонкое, за данными GET по data.id

ПолеТипОписание
idstringId события; повторная доставка приходит с тем же id
typeenumcampaign.sending — отправка началась; campaign.sent — завершена (доставка досчитывается ещё сутки); campaign.failed — не состоялась. Значения: campaign.sending, campaign.sent, campaign.failed
created_atdatetimeКогда событие произошло, UTC
dataEventDataОбъект, с которым произошло событие
{
  "id": "evt_2bX9kQ7m",
  "type": "campaign.sent",
  "created_at": "2026-10-14T09:41:02Z",
  "data": {
    "id": "cmp_Q4n8Rt2v"
  }
}

Журнал событий

GET /v1/events · право campaigns:read

События рассылок по порядку создания — те же, что приходят на вебхук. Для сверки после простоя приёмника передайте в after id последнего обработанного события.

ПараметрГдеОбязателенОписаниеПример
afterqueryId события, после которого отдаватьevt_2bX9kQ7m
typequeryТолько события этого типаcampaign.sent
limitqueryРазмер страницы, от 1 до 100100
cursorquerynext_cursor предыдущей страницы; привязан к фильтрам запросаc_eyJ2IjpbIjIwMjYtMTAtMTMiXX0
curl https://app.lazycrm.ru/v1/events \
  -H "Authorization: Bearer lcrm_live_…"

Ошибки: 400 unknown_parameter, 400 invalid_cursor, 401 missing_api_key, 401 invalid_api_key, 403 insufficient_scope, 422 validation_error, 429 rate_limited, 500 internal_error, 503 upstream_unavailable.

Событие рассылки на вебхук ресторана

POST на адрес вебхука

LazyCRM шлёт POST на адрес из кабинета, когда рассылка из API меняет состояние. Ответьте любым 2xx в течение 10 секунд; иначе будут повторы. Подпись проверяйте до разбора тела — алгоритм в описании раздела events.

ПараметрГдеОбязателенОписаниеПример
webhook-idзаголовокдаId события, он же id в теле; по нему отбрасывайте повторыevt_2bX9kQ7m
webhook-timestampзаголовокдаМомент отправки, секунды Unix; запрос старше 5 минут отклоняйте1792921262
webhook-signatureзаголовокдаПодписи через пробел в виде v1,<base64 HMAC-SHA256>v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=

Тело — объект Event:

ПолеТипОбязательноОписание
idstringдаId события; повторная доставка приходит с тем же id
typeenumдаcampaign.sending — отправка началась; campaign.sent — завершена (доставка досчитывается ещё сутки); campaign.failed — не состоялась. Значения: campaign.sending, campaign.sent, campaign.failed
created_atdatetimeдаКогда событие произошло, UTC
dataEventDataдаОбъект, с которым произошло событие