Публичный API и вебхуки
REST API даёт вашей CRM, бэкенду сайта или собственному боту работать с лидами и диалогами cenaly.ge так же, как это делает панель: читать карточки, менять свойства, отправлять события, отвечать в диалогах. Вебхуки, наоборот, сами сообщают вашему серверу о новых лидах, событиях и сообщениях.
Что нужно для запуска#
| Что | Где |
|---|---|
| Роль | владелец аккаунта — ключ действует от его имени; сотрудники ключей не видят |
| Раздел | включённый чат (лиды и диалоги живут в нём) |
| Ключ | Интеграции → API и вебхуки → Ключи → Создать ключ |
| Адрес API | https://api.cenaly.ge/public-api/v1 |
| Справочник по методам | api.cenaly.ge/public-api/v1/docs |
| OpenAPI 3.1 | api.cenaly.ge/public-api/v1/openapi.json |
Шаг 1. Ключ и права#
- Откройте Интеграции и нажмите API и вебхуки в шапке страницы.
- На вкладке Ключи нажмите Создать ключ, введите название («CRM», «Бэкенд сайта», «Telegram-бот»).
- Выберите набор прав или отметьте права по одному, при нескольких точках — к каким точкам ключ допущен, и срок.
- Скопируйте секрет
cnk_…. Он показывается один раз: у нас хранится только его отпечаток (SHA-256).
| Право | Что даёт |
|---|---|
contacts:read |
список, поиск и карточка лида, свойства |
contacts:write |
менять свойства и теги, склеивать, удалять по запросу субъекта |
events:read |
лента событий лида |
events:write |
отправлять события (покупка, регистрация, любое своё) |
conversations:read |
диалоги и сообщения |
conversations:write |
ответ оператора, заметка, статус, ответственный, метки |
messages:send |
сообщение лиду в его последний диалог |
segments:read |
сохранённые сегменты и их участники |
Наборы: CRM / бэкенд (лиды, свойства, события, чтение диалогов и сегментов), Свой бот (читает лидов, отвечает в диалогах, пишет лидам), Только чтение, Всё.
- Права меняют права и точки ключа на лету — интеграция продолжает работать.
- Перевыпустить выдаёт новый секрет; старый перестаёт работать сразу, права и журнал остаются.
- Отозвать — сразу и навсегда, следующий запрос получит
401.
Ключ передаётся заголовком Authorization: Bearer cnk_… (или X-Api-Key: cnk_…). Храните его только на сервере — не в браузере и не в мобильном приложении.
Шаг 2. Первые запросы#
KEY=cnk_ваш_ключ
API=https://api.cenaly.ge/public-api/v1
# что умеет ключ: права, точки, лимит
curl -H "Authorization: Bearer $KEY" "$API/me"
# лиды, свежие сверху (20 на страницу)
curl -H "Authorization: Bearer $KEY" "$API/contacts?limit=20"
# поиск по имени, почте или телефону
curl -H "Authorization: Bearer $KEY" "$API/contacts?q=anna"
Ответ — всегда конверт:
{
"meta": { "status": 200, "requestId": "…", "nextCursor": "WyIyMDI2LTEwLTA0…" },
"data": { "total": 128, "contacts": [ { "id": "…", "status": "lead", "name": "Анна", "updatedAt": "2026-10-04T09:12:00Z" } ] }
}
Следующая страница — тот же запрос с cursor=<meta.nextCursor>; нет nextCursor — страниц больше нет. Ошибка — {"meta": {...}, "error": {"code": "…"}}.
Точка. Если ключу доступна одна точка, её указывать не нужно. Если несколько — добавьте location=<id точки> (список — GET /v1/locations), иначе ответ 400 location_required.
Свойства и события по вашему user_id. Не обязательно хранить наш id лида: добавьте ?by=user_id, и адресом станет ваш идентификатор пользователя. Лида с таким user_id ещё нет — мы его заведём.
# свойства: операции update_or_create, set_once, add, delete, append, union, exclude
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"ops":[{"op":"update_or_create","key":"$email","value":"anna@example.com"},
{"op":"add","key":"orders","value":1},
{"op":"union","key":"interests","value":"yoga"}]}' \
"$API/contacts/u-1001/props?by=user_id"
# события пачкой (до 100), повтор с тем же id засчитывается один раз
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"events":[{"id":"ord-5531","userId":"u-1001","name":"order_paid","props":{"sum":1450,"currency":"RUB"}}]}' \
"$API/events"
# ответ в диалоге и смена статуса
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"text":"Здравствуйте! Заказ передан курьеру."}' "$API/conversations/<id>/reply"
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"status":"resolved"}' "$API/conversations/<id>/status"
Запись идёт через ту же очередь, что правки из панели: изменения применяются за секунды, а ответ на запись по user_id — 202 с pending. В карточке лида автор правки виден как «API: <название ключа>».
Методы#
| Метод | Что делает | Право |
|---|---|---|
GET /v1/me, GET /v1/locations |
ключ, права, точки | — |
GET /v1/contacts |
лиды: status (anon, lead, user), q, limit, cursor |
contacts:read |
GET /v1/contacts/{id} |
карточка: свойства, теги, сводка событий | contacts:read |
POST /v1/contacts/{id}/props |
свойства операциями (до 250) или {"props":{…}} |
contacts:write |
POST / DELETE /v1/contacts/{id}/tags |
теги лида | contacts:write |
POST /v1/contacts/merge |
склейка двух карточек: превью, затем "apply": true |
contacts:write |
POST /v1/contacts/{id}/erase |
удаление по запросу субъекта ("confirm": true) |
contacts:write |
GET /v1/contacts/{id}/events |
лента событий лида | events:read |
POST /v1/contacts/{id}/events, POST /v1/events |
события (до 100 за раз) | events:write |
GET /v1/contacts/{id}/conversations |
диалоги лида | conversations:read |
POST /v1/contacts/{id}/messages |
написать лиду в его последний диалог | messages:send |
GET /v1/conversations, /{id}, /{id}/messages |
диалоги и сообщения | conversations:read |
POST /v1/conversations/{id}/reply |
ответ оператора или заметка ("type": "note") |
conversations:write |
POST /v1/conversations/{id}/status, /assign, /tags |
статус, ответственный, метки | conversations:write |
GET /v1/segments, GET /v1/segments/{id}/contacts |
сегменты и их участники | segments:read |
Поля, примеры и коды ошибок каждого метода — в справочнике.
Шаг 3. Вебхуки#
Вебхуки настраиваются у точки: Чат → Настройки → Вебхуки — адрес https, события и секрет подписи. К событиям диалога (новый диалог, новое сообщение, статус, оценка, метки) добавились события лида:
| Событие | Когда приходит |
|---|---|
lead.created |
появился новый лид (контакт оставлен в чате, форме или заведён через API) |
lead.props_changed |
изменились свойства лида — список ключей в changedProps |
lead.event_tracked |
у лида событие; по умолчанию все ваши события без системных ($…), список имён задаётся полем «Какие события слать» |
message.goal_reached |
лид достиг цели сообщения (поп-ап, рассылка) |
{
"event": "lead.event_tracked",
"deliveryId": "WD…",
"at": "2026-10-04T09:12:03Z",
"webhookId": "…",
"locationId": "…",
"contact": { "id": "…", "status": "user", "userId": "u-1001", "props": { "orders": 3 }, "tags": ["vip"] },
"leadEvent": { "name": "order_paid", "at": "2026-10-04T09:12:00Z", "props": { "sum": 1450 } }
}
Имя, почта и телефон лида попадают в тело, только если у вебхука включена галка «Передавать контакты гостя». Проверка подписи — HMAC-SHA256 тела секретом вебхука:
# заголовок X-Meni-Signature: sha256=<hex>
echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET"
Ответьте 2xx за 5 секунд — иначе доставка повторится; после длинной серии неудач вебхук отключается, и это видно в настройках. Дубли отсекайте по deliveryId.
Проверить журнал вызовов#
Если интеграция перестала получать данные, откройте «Интеграции» → «API и вебхуки» → «Журнал вызовов», выберите ключ и период. Доступны последние 14 дней; для быстрой проверки можно выбрать 1, 3 или 7 дней.
В записи видны время и ключ, HTTP-метод, путь без идентификаторов, код ответа, ошибка при её наличии и длительность в миллисекундах. IP показан в подсказке при наведении на результат запроса. Тел запросов и ответов в журнале нет: так содержимое карточек и персональные данные не дублируются в технической истории. По журналу можно проверить результат вызова, но нельзя восстановить полный обмен сообщениями.
Если нужной записи нет, проверьте выбранный ключ и расширьте период до 14 дней. Более старые вызовы в этом окне не показываются.
Нужны продажи во внешней BI-системе#
Управляющий сети Москва–Казань хочет передавать продажи в свою систему аналитики. Ключ публичного API продажи не отдаёт: права относятся только к лидам, событиям лидов, диалогам, сообщениям и сегментам. Даже набор «Всё» не добавляет методы заказов и чеков.
Для передачи новых событий заказа настройте сценарий:
- Откройте «Настройки» → «Автоматизация статусов» → «Сценарии (Flow)» и нажмите «Добавить сценарий».
- В «Когда» выберите «Заказ оплачен». Для других задач доступны «Заказ оформлен», «Статус заказа изменился» и «Заказ отменён».
- В «Тогда» добавьте действие «Вызвать вебхук» и укажите адрес обработчика вашей интеграции. При необходимости задайте условия.
- Дождитесь «Сохранено», проведите подходящий тестовый заказ и проверьте получение события на стороне обработчика.
Результат — вызов вашего обработчика при подходящем событии. Загрузку в BI и сопоставление полей настраивает интегратор; сценарий не заменяет выгрузку всей прошлой истории. Если событие не пришло, проверьте, включён ли сценарий, совпали ли событие и все условия, верен ли адрес обработчика. Журнал публичного API показывает входящие вызовы по ключам; доставку этого исходящего вебхука проверяйте на принимающей стороне.
Для разового анализа выгрузите список заказов через «Выгрузить CSV» или подготовьте архив данных. Это ручные способы, без обещания автоматического обновления BI по расписанию.
Ограничения#
- 60 запросов в минуту на ключ; сверх —
429с заголовкомRetry-After. Остаток — вX-RateLimit-*. - До 200 записей на страницу (по умолчанию 50), до 100 событий в пачке, до 250 операций со свойствами за запрос, до 30 тегов за раз.
- До 20 живых ключей на аккаунт.
- «Журнал вызовов» показывает последние 14 дней. Тел запросов и ответов нет; метод, путь без идентификаторов, результат, ошибка, длительность и IP помогают разобрать сбой без копирования содержимого карточек.
- События, отправленные через API, ложатся в карточку лида (лента, сводка, сегменты), но не в сырой журнал аналитики посещений.
- Написать лиду можно только в существующий диалог: нет диалога — ответ
409 no_conversation.
Устранение неполадок#
| Ответ | Что значит | Что делать |
|---|---|---|
401 api_key_missing / api_key_invalid |
ключа нет в запросе, либо он неверный, отозван или истёк | проверьте заголовок; при необходимости перевыпустите ключ |
403 scope_required |
у ключа нет нужного права | Права у ключа — добавьте право |
400 location_required |
ключу доступно несколько точек | добавьте location=<id> |
404 location_not_found |
точки нет среди точек ключа | сверьтесь с GET /v1/locations |
404 not_found |
лида или диалога нет | для своих id используйте ?by=user_id |
429 rate_limited |
больше 60 запросов в минуту | подождите Retry-After секунд, группируйте события пачками |
502 upstream_error |
временный сбой | повторите запрос позже |
Каждый запрос виден на вкладке Журнал вызовов — с кодом ответа и названием ключа.
Частые вопросы#
Можно ли вызывать API из браузера? Нет: ключ даёт доступ ко всем лидам точки. Вызывайте API со своего сервера.
Чем user_id отличается от id лида? id лида — наш идентификатор карточки. user_id — ваш идентификатор пользователя (номер в CRM, id аккаунта на сайте); с ?by=user_id карточку можно адресовать им.
Что будет при повторной отправке события? Событие с тем же id засчитывается один раз — можно смело повторять запрос при сетевой ошибке.
Нужен ли отдельный ключ на каждую точку? Нет: один ключ может работать с несколькими точками, точка выбирается параметром location.
Связанные разделы#
- Чат с гостями — диалоги, лиды и настройки вебхуков
- Заявки — единый входящий поток
- API и MCP своей АТС — отдельный API телефонии
- Интеграции