Publiczne API i webhooki
REST API pozwala Twojemu CRM, backendowi strony lub własnemu botowi pracować z leadami i dialogami cenaly.com tak samo, jak robi to panel: czytać karty, zmieniać właściwości, wysyłać zdarzenia, odpowiadać w dialogach. Webhooki natomiast same informują Twój serwer o nowych leadach, zdarzeniach i wiadomościach.
Co jest potrzebne do startu#
| Co | Gdzie |
|---|---|
| Rola | właściciel konta — klucz działa w jego imieniu; pracownicy nie widzą kluczy |
| Sekcja | włączony czat (leady i dialogi znajdują się w nim) |
| Klucz | Integracje → API i webhooki → Klucze → Utwórz klucz |
| Adres API | https://api.cenaly.com/public-api/v1 |
| Dokumentacja metod | api.cenaly.com/public-api/v1/docs |
| OpenAPI 3.1 | api.cenaly.com/public-api/v1/openapi.json |
Krok 1. Klucz i uprawnienia#
- Otwórz Integracje i kliknij API i webhooki w nagłówku strony.
- Na zakładce Klucze kliknij Utwórz klucz, wpisz nazwę („CRM”, „Backend strony”, „Bot Telegram”).
- Wybierz zestaw uprawnień lub zaznacz uprawnienia pojedynczo, przy kilku placówkach — do których placówek klucz ma dostęp, oraz termin.
- Skopiuj sekret
cnk_…. Jest pokazywany tylko raz: przechowujemy wyłącznie jego odcisk (SHA-256).
| Uprawnienie | Co daje |
|---|---|
contacts:read |
lista, wyszukiwanie i karta leada, właściwości |
contacts:write |
zmiana właściwości i tagów, scalanie, usuwanie na żądanie podmiotu |
events:read |
strumień zdarzeń leada |
events:write |
wysyłanie zdarzeń (zakup, rejestracja, dowolne własne) |
conversations:read |
dialogi i wiadomości |
conversations:write |
odpowiedź operatora, notatka, status, osoba odpowiedzialna, etykiety |
messages:send |
wiadomość do leada w jego ostatnim dialogu |
segments:read |
zapisane segmenty i ich uczestnicy |
Zestawy: CRM / backend (leady, właściwości, zdarzenia, odczyt dialogów i segmentów), Własny bot (czyta leady, odpowiada w dialogach, pisze do leadów), Tylko odczyt, Wszystko.
- Uprawnienia zmieniają uprawnienia i placówki klucza w locie — integracja działa dalej.
- Wygeneruj ponownie wydaje nowy sekret; stary przestaje działać natychmiast, uprawnienia i dziennik pozostają.
- Odwołaj — natychmiast i na zawsze, następne żądanie otrzyma
401.
Klucz przekazuje się nagłówkiem Authorization: Bearer cnk_… (lub X-Api-Key: cnk_…). Przechowuj go wyłącznie na serwerze — nie w przeglądarce i nie w aplikacji mobilnej.
Krok 2. Pierwsze żądania#
KEY=cnk_ваш_ключ
API=https://api.cenaly.com/public-api/v1
# co potrafi klucz: uprawnienia, placówki, limit
curl -H "Authorization: Bearer $KEY" "$API/me"
# leady, najnowsze na górze (20 na stronę)
curl -H "Authorization: Bearer $KEY" "$API/contacts?limit=20"
# wyszukiwanie po imieniu, e-mailu lub telefonie
curl -H "Authorization: Bearer $KEY" "$API/contacts?q=anna"
Odpowiedź to zawsze koperta:
{
"meta": { "status": 200, "requestId": "…", "nextCursor": "WyIyMDI2LTEwLTA0…" },
"data": { "total": 128, "contacts": [ { "id": "…", "status": "lead", "name": "Анна", "updatedAt": "2026-10-04T09:12:00Z" } ] }
}
Następna strona — to samo żądanie z cursor=<meta.nextCursor>; brak nextCursor — nie ma więcej stron. Błąd — {"meta": {...}, "error": {"code": "…"}}.
Placówka. Jeśli klucz ma dostęp do jednej placówki, nie trzeba jej podawać. Jeśli do kilku — dodaj location=<id placówki> (lista — GET /v1/locations), inaczej odpowiedź 400 location_required.
Właściwości i zdarzenia po Twoim user_id. Nie musisz przechowywać naszego id leada: dodaj ?by=user_id, a adresem stanie się Twój identyfikator użytkownika. Jeśli leada z takim user_id jeszcze nie ma — utworzymy go.
# właściwości: operacje 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"
# zdarzenia paczką (do 100), powtórzenie z tym samym id liczy się raz
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"
# odpowiedź w dialogu i zmiana statusu
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"
Zapis przechodzi przez tę samą kolejkę co zmiany z panelu: zmiany są stosowane w ciągu sekund, a odpowiedź na zapis po user_id — 202 z pending. W karcie leada autor zmiany jest widoczny jako „API:
Metody#
| Metoda | Co robi | Uprawnienie |
|---|---|---|
GET /v1/me, GET /v1/locations |
klucz, uprawnienia, placówki | — |
GET /v1/contacts |
leady: status (anon, lead, user), q, limit, cursor |
contacts:read |
GET /v1/contacts/{id} |
karta: właściwości, tagi, podsumowanie zdarzeń | contacts:read |
POST /v1/contacts/{id}/props |
właściwości operacjami (do 250) lub {"props":{…}} |
contacts:write |
POST / DELETE /v1/contacts/{id}/tags |
tagi leada | contacts:write |
POST /v1/contacts/merge |
scalanie dwóch kart: podgląd, następnie "apply": true |
contacts:write |
POST /v1/contacts/{id}/erase |
usunięcie na żądanie podmiotu ("confirm": true) |
contacts:write |
GET /v1/contacts/{id}/events |
strumień zdarzeń leada | events:read |
POST /v1/contacts/{id}/events, POST /v1/events |
zdarzenia (do 100 naraz) | events:write |
GET /v1/contacts/{id}/conversations |
rozmowy leada | conversations:read |
POST /v1/contacts/{id}/messages |
napisanie do leada w jego ostatniej rozmowie | messages:send |
GET /v1/conversations, /{id}, /{id}/messages |
rozmowy i wiadomości | conversations:read |
POST /v1/conversations/{id}/reply |
odpowiedź operatora lub notatka ("type": "note") |
conversations:write |
POST /v1/conversations/{id}/status, /assign, /tags |
status, osoba odpowiedzialna, etykiety | conversations:write |
GET /v1/segments, GET /v1/segments/{id}/contacts |
segmenty i ich uczestnicy | segments:read |
Pola, przykłady i kody błędów każdej metody — w dokumentacji.
Krok 3. Webhooki#
Webhooki konfiguruje się przy placówce: Czat → Ustawienia → Webhooki — adres https, zdarzenia i sekret podpisu. Do zdarzeń rozmowy (nowa rozmowa, nowa wiadomość, status, ocena, etykiety) doszły zdarzenia leada:
| Zdarzenie | Kiedy przychodzi |
|---|---|
lead.created |
pojawił się nowy lead (kontakt pozostawiony w czacie, formularzu lub utworzony przez API) |
lead.props_changed |
zmieniły się właściwości leada — lista kluczy w changedProps |
lead.event_tracked |
lead ma zdarzenie; domyślnie wszystkie Twoje zdarzenia bez systemowych ($…), lista nazw jest określana polem „Jakie zdarzenia wysyłać” |
message.goal_reached |
lead osiągnął cel wiadomości (pop-up, wysyłka) |
{
"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 } }
}
Imię, e-mail i telefon leada trafiają do treści tylko wtedy, gdy w webhooku jest zaznaczona opcja „Przekazuj kontakty gościa”. Weryfikacja podpisu — HMAC-SHA256 treści sekretem webhooka:
# nagłówek X-Meni-Signature: sha256=<hex>
echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET"
Odpowiedz 2xx w ciągu 5 sekund — inaczej dostarczenie zostanie powtórzone; po długiej serii niepowodzeń webhook zostaje wyłączony i widać to w ustawieniach. Duplikaty odrzucaj po deliveryId.
Ograniczenia#
- 60 żądań na minutę na klucz; powyżej —
429z nagłówkiemRetry-After. Pozostały limit — wX-RateLimit-*. - Do 200 rekordów na stronę (domyślnie 50), do 100 zdarzeń w paczce, do 250 operacji na właściwościach na żądanie, do 30 tagów naraz.
- Do 20 aktywnych kluczy na konto.
- Dziennik wywołań klucza jest przechowywany 30 dni: czas, metoda, wzorzec ścieżki (bez id i treści), kod odpowiedzi, czas trwania.
- Zdarzenia wysłane przez API trafiają do karty leada (strumień, podsumowanie, segmenty), ale nie do surowego dziennika analityki odwiedzin.
- Napisać do leada można tylko w istniejącej rozmowie: brak rozmowy — odpowiedź
409 no_conversation.
Rozwiązywanie problemów#
| Odpowiedź | Co oznacza | Co zrobić |
|---|---|---|
401 api_key_missing / api_key_invalid |
w żądaniu nie ma klucza albo jest nieprawidłowy, odwołany lub wygasł | sprawdź nagłówek; w razie potrzeby ponownie wydaj klucz |
403 scope_required |
klucz nie ma wymaganego uprawnienia | Uprawnienia klucza — dodaj uprawnienie |
400 location_required |
klucz ma dostęp do kilku placówek | dodaj location=<id> |
404 location_not_found |
placówki nie ma wśród placówek klucza | porównaj z GET /v1/locations |
404 not_found |
nie ma leada lub rozmowy | dla własnych id użyj ?by=user_id |
429 rate_limited |
więcej niż 60 żądań na minutę | poczekaj Retry-After sekund, grupuj zdarzenia w paczki |
502 upstream_error |
tymczasowa awaria | powtórz żądanie później |
Każde żądanie jest widoczne na zakładce Dziennik wywołań — z kodem odpowiedzi i nazwą klucza.
Częste pytania#
Czy można wywoływać API z przeglądarki? Nie: klucz daje dostęp do wszystkich leadów placówki. Wywołuj API ze swojego serwera.
Czym user_id różni się od id leada? id leada — nasz identyfikator karty. user_id — Twój identyfikator użytkownika (numer w CRM, id konta na stronie); z ?by=user_id kartę można adresować nim.
Co się stanie przy ponownym wysłaniu zdarzenia? Zdarzenie z tym samym id jest liczone raz — można śmiało powtarzać żądanie przy błędzie sieci.
Czy potrzebny jest osobny klucz na każdą placówkę? Nie: jeden klucz może pracować z kilkoma placówkami, placówkę wybiera się parametrem location.
Powiązane sekcje#
- Czat z gośćmi — rozmowy, leady i ustawienia webhooków
- Zgłoszenia — jednolity strumień przychodzący
- API i MCP własnej centrali — osobne API telefonii
- Integracje