API Publik dan Webhook
REST API memungkinkan CRM, backend situs, atau bot Anda sendiri bekerja dengan lead dan percakapan cenaly.com seperti yang dilakukan panel: membaca kartu, mengubah properti, mengirim peristiwa, membalas di percakapan. Sebaliknya, webhook memberi tahu server Anda sendiri tentang lead, peristiwa, dan pesan baru.
Yang diperlukan untuk memulai#
| Apa | Di mana |
|---|---|
| Peran | pemilik akun — kunci berlaku atas namanya; karyawan tidak melihat kunci |
| Bagian | chat yang aktif (lead dan percakapan berada di dalamnya) |
| Kunci | Integrasi → API dan webhook → Kunci → Buat kunci |
| Alamat API | https://api.cenaly.com/public-api/v1 |
| Referensi metode | api.cenaly.com/public-api/v1/docs |
| OpenAPI 3.1 | api.cenaly.com/public-api/v1/openapi.json |
Langkah 1. Kunci dan hak akses#
- Buka Integrasi dan klik API dan webhook di bagian atas halaman.
- Di tab Kunci, klik Buat kunci, masukkan nama (“CRM”, “Backend situs”, “Bot Telegram”).
- Pilih kumpulan hak akses atau centang hak akses satu per satu, jika ada beberapa cabang — cabang mana yang boleh diakses kunci, dan masa berlakunya.
- Salin secret
cnk_…. Ini hanya ditampilkan sekali: kami hanya menyimpan sidik jarinya (SHA-256).
| Hak akses | Apa yang diberikan |
|---|---|
contacts:read |
daftar, pencarian, dan kartu lead, properti |
contacts:write |
mengubah properti dan tag, menggabungkan, menghapus atas permintaan subjek |
events:read |
feed peristiwa lead |
events:write |
mengirim peristiwa (pembelian, pendaftaran, apa pun milik Anda) |
conversations:read |
percakapan dan pesan |
conversations:write |
balasan operator, catatan, status, penanggung jawab, label |
messages:send |
pesan ke lead di percakapan terakhirnya |
segments:read |
segmen tersimpan dan anggotanya |
Kumpulan: CRM / backend (lead, properti, peristiwa, baca percakapan dan segmen), Bot sendiri (membaca lead, membalas di percakapan, menulis ke lead), Hanya baca, Semua.
- Hak akses mengubah hak akses dan cabang kunci secara langsung — integrasi tetap berjalan.
- Terbitkan ulang menerbitkan secret baru; yang lama langsung berhenti berfungsi, hak akses dan log tetap ada.
- Cabut — langsung dan selamanya, permintaan berikutnya akan mendapat
401.
Kunci dikirim melalui header Authorization: Bearer cnk_… (atau X-Api-Key: cnk_…). Simpan hanya di server — bukan di browser dan bukan di aplikasi seluler.
Langkah 2. Permintaan pertama#
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"
Responsnya selalu berupa envelope:
{
"meta": { "status": 200, "requestId": "…", "nextCursor": "WyIyMDI2LTEwLTA0…" },
"data": { "total": 128, "contacts": [ { "id": "…", "status": "lead", "name": "Анна", "updatedAt": "2026-10-04T09:12:00Z" } ] }
}
Halaman berikutnya — permintaan yang sama dengan cursor=<meta.nextCursor>; tidak ada nextCursor — tidak ada halaman lagi. Kesalahan — {"meta": {...}, "error": {"code": "…"}}.
Cabang. Jika kunci hanya memiliki akses ke satu cabang, tidak perlu menyebutkannya. Jika ada beberapa — tambahkan location=<id cabang> (daftar — GET /v1/locations), jika tidak responsnya 400 location_required.
Properti dan peristiwa berdasarkan user_id Anda. Tidak wajib menyimpan id lead kami: tambahkan ?by=user_id, dan alamatnya akan menjadi pengenal pengguna Anda. Jika lead dengan user_id tersebut belum ada — kami akan membuatnya.
# свойства: операции 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"
Penulisan melewati antrean yang sama dengan pengeditan dari panel: perubahan diterapkan dalam hitungan detik, dan respons terhadap penulisan berdasarkan user_id — 202 dengan pending. Di kartu lead, penulis pengeditan terlihat sebagai “API:
Metode#
| Metode | Fungsinya | Hak |
|---|---|---|
GET /v1/me, GET /v1/locations |
kunci, hak, cabang | — |
GET /v1/contacts |
lead: status (anon, lead, user), q, limit, cursor |
contacts:read |
GET /v1/contacts/{id} |
kartu: properti, tag, ringkasan peristiwa | contacts:read |
POST /v1/contacts/{id}/props |
properti lewat operasi (hingga 250) atau {"props":{…}} |
contacts:write |
POST / DELETE /v1/contacts/{id}/tags |
tag lead | contacts:write |
POST /v1/contacts/merge |
penggabungan dua kartu: pratinjau, lalu "apply": true |
contacts:write |
POST /v1/contacts/{id}/erase |
penghapusan atas permintaan subjek ("confirm": true) |
contacts:write |
GET /v1/contacts/{id}/events |
linimasa peristiwa lead | events:read |
POST /v1/contacts/{id}/events, POST /v1/events |
peristiwa (hingga 100 sekaligus) | events:write |
GET /v1/contacts/{id}/conversations |
percakapan lead | conversations:read |
POST /v1/contacts/{id}/messages |
kirim pesan ke lead di percakapan terakhirnya | messages:send |
GET /v1/conversations, /{id}, /{id}/messages |
percakapan dan pesan | conversations:read |
POST /v1/conversations/{id}/reply |
balasan operator atau catatan ("type": "note") |
conversations:write |
POST /v1/conversations/{id}/status, /assign, /tags |
status, penanggung jawab, label | conversations:write |
GET /v1/segments, GET /v1/segments/{id}/contacts |
segmen dan anggotanya | segments:read |
Kolom, contoh, dan kode kesalahan setiap metode ada di referensi.
Langkah 3. Webhook#
Webhook dikonfigurasi per cabang: Chat → Pengaturan → Webhook — alamat https, peristiwa, dan rahasia tanda tangan. Selain peristiwa percakapan (percakapan baru, pesan baru, status, penilaian, label), kini ada peristiwa lead:
| Peristiwa | Kapan dikirim |
|---|---|
lead.created |
lead baru muncul (kontak ditinggalkan di chat, formulir, atau dibuat lewat API) |
lead.props_changed |
properti lead berubah — daftar kunci ada di changedProps |
lead.event_tracked |
lead memiliki peristiwa; secara bawaan semua peristiwa Anda tanpa peristiwa sistem ($…), daftar nama diatur lewat kolom "Peristiwa apa yang dikirim" |
message.goal_reached |
lead mencapai tujuan pesan (pop-up, siaran) |
{
"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 } }
}
Nama, email, dan telepon lead masuk ke isi permintaan hanya jika webhook mengaktifkan centang "Teruskan kontak tamu". Verifikasi tanda tangan — HMAC-SHA256 isi permintaan dengan rahasia webhook:
# заголовок X-Meni-Signature: sha256=<hex>
echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET"
Balas 2xx dalam 5 detik — jika tidak, pengiriman akan diulang; setelah rangkaian kegagalan yang panjang, webhook dinonaktifkan dan ini terlihat di pengaturan. Saring duplikat berdasarkan deliveryId.
Batasan#
- 60 permintaan per menit per kunci; lebih dari itu —
429dengan headerRetry-After. Sisa kuota ada diX-RateLimit-*. - Hingga 200 rekaman per halaman (bawaan 50), hingga 100 peristiwa per batch, hingga 250 operasi properti per permintaan, hingga 30 tag sekaligus.
- Hingga 20 kunci aktif per akun.
- Log pemanggilan kunci disimpan 30 hari: waktu, metode, pola jalur (tanpa id dan isi permintaan), kode respons, durasi.
- Peristiwa yang dikirim lewat API masuk ke kartu lead (linimasa, ringkasan, segmen), tetapi tidak ke log mentah analitik kunjungan.
- Pesan ke lead hanya bisa dikirim ke percakapan yang sudah ada: jika tidak ada percakapan — respons
409 no_conversation.
Pemecahan masalah#
| Respons | Artinya | Tindakan |
|---|---|---|
401 api_key_missing / api_key_invalid |
kunci tidak ada di permintaan, atau tidak valid, dicabut, atau kedaluwarsa | periksa header; jika perlu, terbitkan ulang kunci |
403 scope_required |
kunci tidak memiliki hak yang diperlukan | Hak pada kunci — tambahkan hak |
400 location_required |
kunci memiliki akses ke beberapa cabang | tambahkan location=<id> |
404 location_not_found |
cabang tidak ada di antara cabang kunci | cocokkan dengan GET /v1/locations |
404 not_found |
lead atau percakapan tidak ada | untuk id Anda sendiri gunakan ?by=user_id |
429 rate_limited |
lebih dari 60 permintaan per menit | tunggu Retry-After detik, kelompokkan peristiwa dalam batch |
502 upstream_error |
gangguan sementara | ulangi permintaan nanti |
Setiap permintaan terlihat di tab Log pemanggilan — dengan kode respons dan nama kunci.
Pertanyaan umum#
Bisakah API dipanggil dari browser? Tidak: kunci memberi akses ke semua lead cabang. Panggil API dari server Anda sendiri.
Apa bedanya user_id dengan id lead? id lead adalah pengenal kartu dari kami. user_id adalah pengenal pengguna dari Anda (nomor di CRM, id akun di situs); dengan ?by=user_id kartu dapat dialamatkan dengannya.
Apa yang terjadi jika peristiwa dikirim ulang? Peristiwa dengan id yang sama dihitung sekali — permintaan boleh diulang dengan aman saat terjadi kesalahan jaringan.
Apakah perlu kunci terpisah untuk setiap cabang? Tidak: satu kunci dapat bekerja dengan beberapa cabang, cabang dipilih lewat parameter location.
Bagian terkait#
- Chat dengan tamu — percakapan, lead, dan pengaturan webhook
- Permintaan — alur masuk terpadu
- API dan MCP PBX Anda — API teleponi terpisah
- Integrasi