Јавен API и вебхуци
REST API му овозможува на вашиот CRM, бекендот на сајтот или сопствениот бот да работат со лидови и разговори на cenaly.com исто како што тоа го прави панелот: да читаат картички, да менуваат својства, да испраќаат настани, да одговараат во разговори. Вебхуците, пак, самите го известуваат вашиот сервер за нови лидови, настани и пораки.
Што е потребно за стартување#
| Што | Каде |
|---|---|
| Улога | сопственик на сметката — клучот дејствува во негово име; вработените не гледаат клучеви |
| Раздел | вклучен чат (лидовите и разговорите живеат во него) |
| Клуч | Интеграции → API и вебхуци → Клучеви → Создај клуч |
| Адреса на API | https://api.cenaly.com/public-api/v1 |
| Референтен водич за методите | api.cenaly.com/public-api/v1/docs |
| OpenAPI 3.1 | api.cenaly.com/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.com/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":45,"currency":"GEL"}}]}' \
"$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": 45 } }
}
Името, е-поштата и телефонот на лидот влегуваат во телото само ако кај вебхукот е вклучено полето „Пренесувај контакти на гостинот“. Проверката на потписот е HMAC-SHA256 на телото со тајната на вебхукот:
# заголовок X-Meni-Signature: sha256=<hex>
echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET"
Одговорете 2xx за 5 секунди — инаку доставата се повторува; по долга серија неуспеси вебхукот се исклучува и тоа се гледа во поставките. Дубликатите отсекувајте ги по deliveryId.
Ограничувања#
- 60 барања во минута на клуч; над тоа —
429со заглавјеRetry-After. Остатокот — воX-RateLimit-*. - До 200 записи на страница (стандардно 50), до 100 настани во пакет, до 250 операции со својства за барање, до 30 ознаки одеднаш.
- До 20 активни клучеви на сметка.
- Дневникот на повици на клучот се чува 30 дена: време, метод, шаблон на патека (без id и тело), код на одговор, времетраење.
- Настаните испратени преку 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 за телефонија
- Интеграции