API dan MCP untuk PBX Anda
PBX Cenaly Anda terbuka untuk program dan Asisten AI Anda:
- CRM, sistem akuntansi, situs web Anda — REST API: log panggilan, rekaman dan transkripsi, panggilan sekali klik, ekstensi, pengalihan, aturan panggilan;
- Claude Code, Claude Desktop, Cursor — server MCP jarak jauh dengan kunci;
- ChatGPT, claude.ai, Perplexity, Cursor dan VS Code — server MCP yang sama tanpa kunci: Anda masuk ke Akun Anda dan mengizinkan akses (OAuth).
Semuanya berjalan atas nama pemilik Akun dan hanya dengan hak yang ia berikan. Setiap perubahan terlihat di log tindakan PBX dengan nama kunci atau Aplikasi.
Alamat#
| Apa | Alamat |
|---|---|
| REST API | https://api.cenaly.com/pbx-api/v1 |
| Server MCP (streamable HTTP) | https://api.cenaly.com/pbx-api/mcp |
| Dokumentasi metode | api.cenaly.com/pbx-api/v1/docs |
| Deskripsi OpenAPI 3.1 | api.cenaly.com/pbx-api/v1/openapi.json |
| Metadata OAuth | https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api |
Kunci dan hak#
Kunci hanya dibuat oleh pemilik Akun: Telefoni → API dan MCP → Kunci → Buat kunci. Karyawan dengan peran "Administrator PBX" tidak dapat melihat kunci — kunci berlaku atas nama pemilik.
- Kunci berformat
cpx_…ditampilkan satu kali — tepat setelah dibuat, bersama sisipan siap pakai untuk koneksi. Kami hanya menyimpan sidik jarinya (SHA-256), kunci tidak dapat dipulihkan — hanya bisa menerbitkan yang baru. - Kunci dapat dibatasi berdasarkan Cabang (jika tidak — semua Cabang, termasuk yang akan datang) dan masa berlaku (30, 90, 365 hari atau tanpa batas).
- "Hak" mengubah hak dan Cabang kunci secara langsung: Integrasi tetap berjalan, hak baru berlaku mulai permintaan berikutnya.
- "Cabut" — langsung dan selamanya: permintaan berikutnya dengan kunci ini akan mendapat 401.
- Kunci dan koneksi aktif — hingga 20 per Akun.
Hak dipilih dengan set siap pakai atau centang:
| Hak | Apa yang diberikan | Set |
|---|---|---|
calls:read |
log panggilan dan kartu panggilan dengan rute | CRM, Asisten AI, hanya baca, semua |
recordings:read |
tautan ke Rekaman percakapan (10 menit) dan transkripsi | CRM, Asisten AI, hanya baca, semua |
calls:dial |
panggilan sekali klik: telepon karyawan berdering lebih dulu, setelah dijawab PBX menekan Nomor | CRM, Asisten AI, semua |
extensions:read |
ekstensi, grup, pengalihan, "jangan ganggu" | CRM, Asisten AI, hanya baca, semua |
extensions:write |
mengubah pengalihan pribadi dan "jangan ganggu" | Asisten AI, semua |
presence:read |
siapa yang bebas, sedang menelepon, sedang berbicara | Asisten AI, hanya baca, semua |
reports:read |
metrik call center per periode: tingkat layanan, waktu tunggu, panggilan terputus, AHT, FCR, CSAT, di mana panggilan hilang, rincian per antrean, saluran, karyawan | hanya baca, semua |
routes:read |
Nomor, aturan panggilan masuk dan keluar, riwayat aturan | hanya baca, semua |
routes:write |
membuat, mengubah, menghapus dan menyusun ulang aturan panggilan, mengembalikan dari riwayat | hanya dengan centang terpisah |
config:export |
ekspor pengaturan PBX dalam format file | hanya dengan centang terpisah |
config:import |
impor pengaturan dari tabel: pratinjau, lalu penerapan | hanya dengan centang terpisah |
webhooks:write |
membuat, mengubah, menguji dan menghapus webhook peristiwa panggilan | hanya dengan centang terpisah |
daynight:write |
menutup Cabang hingga akhir hari atau hingga tanggal tertentu, membuka — sama seperti *28 dari telepon |
hanya dengan centang terpisah |
Hak yang mengubah sesuatu atau menghabiskan menit ditandai kuning di jendela. Tiga hak terakhir tidak termasuk dalam set mana pun, bahkan "Semua" — hanya dapat diberikan secara sadar, dengan centang terpisah.
ChatGPT, claude.ai, Perplexity, Cursor, VS Code: koneksi tanpa kunci#
Asisten cloud tidak dapat menyisipkan kunci ke header — mereka menghubungkan server MCP melalui OAuth. Kunci tidak perlu dibuat.
claude.ai: Pengaturan → Konektor → Tambah konektor Anda → tempel https://api.cenaly.com/pbx-api/mcp → Hubungkan.
ChatGPT: Pengaturan → Aplikasi dan konektor → Lanjutan → aktifkan mode pengembang → Buat → tempel https://api.cenaly.com/pbx-api/mcp, autentikasi — OAuth.
Perplexity: Pengaturan Akun → Konektor → "+ Konektor Anda" → Jarak jauh → tempel https://api.cenaly.com/pbx-api/mcp, autentikasi — OAuth.
Cursor dan VS Code: tambahkan server MCP jarak jauh (HTTP) dengan alamat https://api.cenaly.com/pbx-api/mcp tanpa header kunci — jendela masuk akan terbuka di browser. Di Cursor: .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}}; di VS Code: perintah "MCP: Add Server" → HTTP.
Selanjutnya asisten akan membuka jendela masuk Cenaly. Setelah masuk Anda akan melihat:
- siapa yang meminta akses — Aplikasi dinamai berdasarkan alamat tempat respons akan dikembalikan: "Konektor terverifikasi · chatgpt.com" (begitu juga — claude.ai, perplexity.ai, vscode.dev, Cursor), "Program di komputer ini" atau peringatan "Alamat tidak dikenal". Nama yang dikirim Aplikasi ditampilkan kecil — siapa pun bisa menulisnya;
- hak — yang ditandai adalah yang diminta Aplikasi (jika ia meminta "semuanya", set "Asisten AI" yang ditandai); hak "hanya dengan centang terpisah" tidak pernah ditandai sebelumnya;
- Cabang — semua atau yang dipilih.
"Izinkan" mengembalikan Anda ke asisten, dan ia langsung melihat alat PBX. Koneksi muncul di Telefoni → API dan MCP → Kunci sebagai baris dengan label OAuth dan alamat Aplikasi — di sana juga hak diubah dan akses dicabut. Menghubungkan ulang Aplikasi yang sama memperbarui haknya, bukan membuat koneksi kedua.
Hanya pemilik Akun yang dapat mengizinkan koneksi.
Claude Code, Claude Desktop, Cursor: koneksi dengan kunci#
Claude Code — satu perintah:
claude mcp add --transport http telephony https://api.cenaly.com/pbx-api/mcp --header "Authorization: Bearer cpx_…"
Claude Desktop, Cursor (.cursor/mcp.json) dan klien lain dengan berkas pengaturan:
{
"mcpServers": {
"telephony": {
"type": "http",
"url": "https://api.cenaly.com/pbx-api/mcp",
"headers": { "Authorization": "Bearer cpx_…" }
}
}
}
Sisipan siap pakai dengan kunci Anda ditampilkan segera setelah kunci dibuat. Asisten AI hanya melihat alat yang diizinkan oleh kunci, dan dapat menjawab “siapa yang menelepon hari ini dan tidak terjawab”, “telepon balik tamu ini dari telepon Anna”, “aktifkan pengalihan ke ponsel untuk saya”.
REST API#
Kunci — di header Authorization: Bearer <ключ> (atau X-Api-Key). Jika kunci Anda memiliki satu cabang, parameter location tidak perlu dikirim; jika beberapa — respons 400 location_required akan mencantumkannya.
| Metode | Jalur | Hak | Fungsinya |
|---|---|---|---|
| GET | /v1/me |
— | hak, cabang, dan limit kunci |
| GET | /v1/locations |
— | cabang kunci dan PBX-nya |
| GET | /v1/calls |
calls:read |
jurnal panggilan: since, until, direction, status (answered, missed, ai), number, extension, limit hingga 100, cursor |
| GET | /v1/calls/{id} |
calls:read |
panggilan dengan rute: aturan mana yang berlaku, telepon siapa yang berdering, siapa yang menjawab |
| GET | /v1/calls/{id}/recording |
recordings:read |
tautan ke rekaman selama 10 menit |
| GET | /v1/calls/{id}/transcript |
recordings:read |
transkrip dan ringkasan percakapan |
| POST | /v1/dial |
calls:dial |
panggilan sekali klik: { "extension": "101", "number": "+995555123456" } |
| GET | /v1/dial/{commandId} |
calls:dial |
status panggilan sekali klik |
| GET | /v1/extensions |
extensions:read |
ekstensi, grup, pengalihan, “jangan ganggu” |
| PUT | /v1/extensions/{ext}/forwarding |
extensions:write |
pengalihan pribadi ekstensi |
| PUT | /v1/extensions/{ext}/dnd |
extensions:write |
“jangan ganggu”: { "on": true } |
| GET | /v1/presence |
presence:read |
siapa yang tersedia saat ini |
| GET | /v1/metrics |
reports:read |
metrik call center per periode: from, to (tanggal lokal cabang YYYY-MM-DD, bawaan — 7 hari terakhir), compare (prev, year, prev,year atau kosong), sections (metrics,loss,queues,lines,operators,directions,heatmap,daily), callbacks=true — juga kecepatan panggilan balik |
| GET | /v1/routes |
routes:read |
nomor, aturan panggilan masuk dan keluar |
| GET | /v1/routes/history |
routes:read |
riwayat perubahan aturan |
| POST, PUT, DELETE | /v1/routes/inbound…, /v1/routes/outbound… |
routes:write |
aturan panggilan satu per satu: buat, ubah bidang yang dikirim, hapus, urutkan ulang, kembalikan |
| GET, POST | /v1/config/export, /v1/config/import |
config:export, config:import |
pengaturan dalam format berkas; unggah — pratinjau, lalu terapkan |
| GET | /v1/events |
calls:read |
peristiwa panggilan cabang selama 7 hari (hingga 2000): since (id peristiwa atau waktu), types, limit (hingga 500 per respons) |
| GET, POST, PATCH, DELETE | /v1/webhooks… |
webhooks:write |
webhook: daftar, buat, ubah, hapus; …/rotate-secret, …/test, …/deliveries |
| GET, PUT | /v1/open-closed |
routes:read, daynight:write |
apakah tutup dan sampai kapan; tutup hingga akhir hari { "closed": true }, hingga tanggal { "closed": true, "until": "2026-10-05T09:00" } atau buka |
Deskripsi lengkap bidang — di halaman dokumentasi dan di OpenAPI.
Siapa yang menelepon hari ini dan tidak terjawab:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/calls?status=missed&since=$(date -u +%Y-%m-%dT00:00:00Z)"
Telepon balik klien dari telepon ekstensi 101:
curl -X POST -H "Authorization: Bearer cpx_…" -H "Content-Type: application/json" \
-d '{"extension":"101","number":"+995555123456"}' "https://api.cenaly.com/pbx-api/v1/dial"
Metrik September dengan perbandingan Agustus dan September tahun lalu — untuk panel BI Anda sendiri:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/metrics?from=2026-09-01&to=2026-09-30&compare=prev,year"
Dalam respons metrics — angka yang sama seperti di layar Telefoni → Jurnal Panggilan → Analitik: panggilan masuk, diterima dan terlewat, tingkat layanan (ambang dan target — dari pengaturan antrean), rata-rata dan maksimum waktu tunggu, proporsi yang dibatalkan tanpa panggilan singkat, AHT, FCR, proporsi pengalihan dan bot, CSAT. compare.prev dan compare.year — bidang yang sama untuk periode sebelumnya dan periode yang sama setahun lalu. Perbandingan dengan tahun lalu dihitung untuk periode hingga 400 hari.
Aktifkan pengalihan ke ponsel jika karyawan tidak menjawab dalam 15 detik:
curl -X PUT -H "Authorization: Bearer cpx_…" -H "Content-Type: application/json" \
-d '{"forward":{"noAnswer":{"kind":"number","number":"+995599000111"},"noAnswerSec":15}}' \
"https://api.cenaly.com/pbx-api/v1/extensions/101/forwarding"
Alat MCP#
Operasi yang sama seperti REST. Klien hanya melihat alat yang diizinkan oleh kunci atau koneksi:
| Alat | Hak |
|---|---|
list_locations |
— |
list_calls, get_call |
calls:read |
get_call_recording, get_call_transcript |
recordings:read |
call_number, get_dial_status |
calls:dial |
list_extensions |
extensions:read |
set_forwarding, set_do_not_disturb |
extensions:write |
get_presence |
presence:read |
get_call_metrics |
reports:read |
list_routes, list_route_history |
routes:read |
save_inbound_rule, delete_inbound_rule, move_inbound_rule, save_outbound_rule, delete_outbound_rule, move_outbound_rule, set_outbound_calls, restore_route_version |
routes:write |
export_config |
config:export |
import_config |
config:import |
get_call_events |
calls:read |
list_webhooks, save_webhook, delete_webhook, rotate_webhook_secret, test_webhook, list_webhook_deliveries |
webhooks:write |
get_open_closed |
routes:read |
set_open_closed |
daynight:write |
Server berjalan tanpa sesi (streamable HTTP, JSON-RPC 2.0): initialize, tools/list, tools/call.
OAuth untuk pengembang konektor sendiri#
Server otorisasi mengikuti spesifikasi otorisasi MCP — klien apa pun yang mendukungnya dapat digunakan:
- Permintaan ke MCP tanpa token menerima 401 dengan header
WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp". - Metadata sumber daya (RFC 9728) menyebutkan server otorisasi —
https://api.cenaly.com/pbx-api; metadatanya (RFC 8414) ada di alamathttps://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api(dan…/pbx-api/.well-known/openid-configuration). - Registrasi dinamis klien (RFC 7591):
POST /pbx-api/oauth/register. Alamat pengembalian — hanyalocalhost/127.0.0.1(port apa pun) atau alamat konektor yang dikenal (claude.ai, claude.com, chatgpt.com, chat.openai.com, vscode.dev, www.perplexity.ai, enterprise.perplexity.ai; untuk Cursor — juga tepatcursor://anysphere.cursor-mcp/oauth/callback). Metode masuk klien —none(klien publik),client_secret_post, atauclient_secret_basic. - Kode otorisasi dengan PKCE (hanya
S256):GET /pbx-api/oauth/authorize→ jendela masuk dan persetujuan pemilik → kembali ke alamat Anda dengancode,state, daniss. Parameterresource— alamat server MCP. - Token:
POST /pbx-api/oauth/token. Kode bersifat sekali pakai dan berlaku 2 menit (code_verifieryang salah membatalkannya); token akses — 1 jam; token pembaruan — 90 hari, setiap pembaruan menerbitkan token baru, token lama berhenti berfungsi. - Pencabutan:
POST /pbx-api/oauth/revoke(RFC 7009) mematikan koneksi sepenuhnya — seperti "Cabut" di jendela "API dan MCP".
Token akses diterima di mana pun kunci diterima: baik di MCP maupun REST, dengan hak dan cabang yang diizinkan pemilik.
Batas dan kesalahan#
- Per kunci atau koneksi: 120 permintaan per menit dan 20.000 per hari (REST dan MCP bersama).
- Panggilan sekali klik — terpisah: 10 per menit dan 300 per hari.
- Log — hingga 100 panggilan per permintaan; di log PBX cabang — 400 panggilan terakhir selama 90 hari.
| Kode | Kesalahan | Yang harus dilakukan |
|---|---|---|
| 401 | api_key_missing, api_key_invalid |
kunci tidak ada, dicabut, atau kedaluwarsa; token OAuth kedaluwarsa — perbarui |
| 403 | scope_required |
kunci tidak memiliki hak — tambahkan di "Hak" |
| 400 | location_required |
kunci memiliki beberapa cabang — sertakan location |
| 404 | location_not_found |
cabang tidak ada atau kunci dibatasi ke cabang lain |
| 429 | rate_limited |
batas tercapai, coba lagi setelah Retry-After detik |
Peristiwa Panggilan#
Secara real-time — webhook PBX: Telefoni → API dan MCP → Webhook atau POST /v1/webhooks dengan kunci berhak webhooks:write. Ke alamat https Anda dalam hitungan detik datang POST untuk setiap peristiwa: call.started (dimulai: arah, siapa, ke mana, saluran), call.ringing (pada siapa berdering — satu per setiap telepon), call.answered (siapa yang menjawab), call.transferred (siapa dan kepada siapa mengalihkan), call.ended (hasil, durasi, percakapan, siapa yang menjawab). Webhook dapat dibatasi pada cabang dan jenis peristiwa.
{ "id": "1727771234.56:2", "type": "call.answered", "createdAt": "2026-10-01T10:00:05Z",
"locationId": "…", "webhookId": "wh_…", "attempt": 1,
"data": { "callId": "1727771234.56", "seq": 2, "direction": "inbound",
"from": { "number": "+995555123456" }, "party": { "extension": "101", "name": "Анна" } } }
Tanda tangan — header X-Cenaly-Signature: t=<waktu unix>,v1=<HMAC-SHA256 dari "t.body" dengan secret webhook>. Hitung ulang, bandingkan dalam waktu konstan dan tolak t yang lebih tua dari 5 menit. Secret whsec_… ditampilkan sekali; "Secret baru" langsung mematikan yang sebelumnya.
Pengiriman — balas 2xx dalam 10 detik. Jika tidak, kami mengulang dengan jeda 10 dtk, 30 dtk, 2, 5, 10, 15 dan 15 menit (8 percobaan, sekitar satu jam); pengulangan membawa id yang sama — gunakan itu untuk membuang duplikat. Log pengiriman (kode respons, waktu, percobaan) — di jendela webhook dan GET /v1/webhooks/{id}/deliveries; "Periksa" mengirim webhook.ping layanan. Alamat 3 hari berturut-turut tidak menerima satu pun pengiriman — webhook mati sendiri: pemilik menerima email, di jendela "Webhook" — tanda "Dimatikan otomatis" dan tombol "Aktifkan" (atau PATCH /v1/webhooks/{id} dengan { "enabled": true }).
Tanpa server sendiri — feed yang sama lewat polling: GET /v1/events?since=<id peristiwa terakhir> atau alat MCP get_call_events (peristiwa cabang selama 7 hari terakhir, hingga 2000; per respons — hingga 500, more: true — lanjutkan dengan since yang sama).
Setelah pemrosesan rekaman — panggilan dengan transkripsi dan analisis datang lewat webhook sumber "Webhook" di bagian "Panggilan".
"Buka / tutup" — PUT /v1/open-closed dengan { "closed": true } menutup cabang hingga akhir hari (seperti *28 dari telepon: panggilan berjalan dengan aturan "di luar jam"), false — membuka; GET menunjukkan apakah tutup dan oleh siapa. Dengan "until" — tutup hingga saat itu (tidak lebih dari 30 hari), lalu terbuka sendiri: waktu tanpa offset (2026-10-05T09:00) dibaca dalam zona cabang; false juga menghapusnya. Perlu centang "Tutup dengan kode *28" yang aktif di perutean (jika tidak 409).
Keamanan#
- Kunci ditampilkan sekali dan disimpan di kami hanya sebagai sidik jari; kunci yang bocor dicabut dengan satu tombol.
- Koneksi OAuth hanya diizinkan oleh pemilik, dan terlihat ke alamat mana akses diberikan; koneksi yang diizinkan dapat dibatasi pada hak dan cabang serta dicabut kapan saja.
- Nomor telepon — data pribadi klien Anda: berikan hak atas log dan rekaman hanya kepada integrasi yang benar-benar membutuhkannya.
- Semua perubahan melalui kunci atau koneksi — di log tindakan PBX dengan nama kunci atau aplikasi.