Документация → События и вебхуки
События и вебхуки
Уведомления о рассылках на ваш адрес и журнал для сверки.
События рассылок: вебхук на адрес ресторана и журнал 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
| Поле | Тип | Описание |
|---|---|---|
id | string | Id события; повторная доставка приходит с тем же id |
type | enum | campaign.sending — отправка началась; campaign.sent — завершена (доставка досчитывается ещё сутки); campaign.failed — не состоялась. Значения: campaign.sending, campaign.sent, campaign.failed |
created_at | datetime | Когда событие произошло, UTC |
data | EventData | Объект, с которым произошло событие |
{
"id": "evt_2bX9kQ7m",
"type": "campaign.sent",
"created_at": "2026-10-14T09:41:02Z",
"data": {
"id": "cmp_Q4n8Rt2v"
}
}Журнал событий
GET /v1/events · право campaigns:read
События рассылок по порядку создания — те же, что приходят на вебхук. Для сверки после
простоя приёмника передайте в after id последнего обработанного события.
| Параметр | Где | Обязателен | Описание | Пример |
|---|---|---|---|---|
after | query | Id события, после которого отдавать | evt_2bX9kQ7m | |
type | query | Только события этого типа | campaign.sent | |
limit | query | Размер страницы, от 1 до 100 | 100 | |
cursor | query | next_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:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
id | string | да | Id события; повторная доставка приходит с тем же id |
type | enum | да | campaign.sending — отправка началась; campaign.sent — завершена (доставка досчитывается ещё сутки); campaign.failed — не состоялась. Значения: campaign.sending, campaign.sent, campaign.failed |
created_at | datetime | да | Когда событие произошло, UTC |
data | EventData | да | Объект, с которым произошло событие |
