API і MCP власної АТС
Власна АТС Cenaly відкрита для ваших програм та ШІ-асистентів:
- CRM, облікова система, власний сайт — REST API: журнал дзвінків, записи та розшифровки, дзвінок в один клік, додаткові, переадресація, правила дзвінків;
- Claude Code, Claude Desktop, Cursor — віддалений MCP-сервер за ключем;
- ChatGPT, claude.ai, Perplexity, Cursor і VS Code — той самий MCP-сервер без ключа: ви входите у свій обліковий запис і дозволяєте доступ (OAuth).
Усе працює від імені власника облікового запису і лише з правами, які він надав. Кожна зміна видна в журналі дій АТС із назвою ключа або додатка.
Адреси#
| Що | Адреса |
|---|---|
| REST API | https://api.cenaly.com/pbx-api/v1 |
| MCP-сервер (streamable HTTP) | https://api.cenaly.com/pbx-api/mcp |
| Документація за методами | api.cenaly.com/pbx-api/v1/docs |
| Опис OpenAPI 3.1 | api.cenaly.com/pbx-api/v1/openapi.json |
| Метадані OAuth | https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api |
Ключ і права#
Ключ створює лише власник облікового запису: Телефонія → API і MCP → Ключі → Створити ключ. Співробітник із роллю «Адміністратор АТС» ключів не бачить — ключ діє від імені власника.
- Ключ виду
cpx_…показується один раз — одразу після створення, разом із готовими вставками для підключення. У нас зберігається лише його відбиток (SHA-256), відновити ключ неможливо — тільки випустити новий. - Ключ можна обмежити точками (інакше — усі точки, включно з майбутніми) і терміном (30, 90, 365 днів або безстроково).
- «Права» змінюють права й точки ключа на льоту: інтеграції продовжують працювати, нові права діють із наступного запиту.
- «Відкликати» — одразу й назавжди: наступний запит із цим ключем отримає 401.
- Живих ключів і підключень — до 20 на обліковий запис.
Права вибираються готовим набором або галочками:
| Право | Що дає | Набори |
|---|---|---|
calls:read |
журнал дзвінків і картка дзвінка з маршрутом | CRM, ШІ-асистент, лише читання, усе |
recordings:read |
посилання на запис розмови (10 хвилин) і розшифровка | CRM, ШІ-асистент, лише читання, усе |
calls:dial |
дзвінок в один клік: спочатку дзвонить телефон співробітника, після відповіді АТС набирає номер | CRM, ШІ-асистент, усе |
extensions:read |
додаткові, групи, переадресація, «не турбувати» | CRM, ШІ-асистент, лише читання, усе |
extensions:write |
змінювати особисту переадресацію та «не турбувати» | ШІ-асистент, усе |
presence:read |
хто вільний, дзвонить, розмовляє | ШІ-асистент, лише читання, усе |
reports:read |
метрики кол-центру за період: рівень обслуговування, очікування, покинуті, AHT, FCR, CSAT, де втрачаємо дзвінки, розрізи за чергами, лініями, співробітниками | лише читання, усе |
routes:read |
номери, правила вхідних і вихідних, історія правил | лише читання, усе |
routes:write |
створювати, змінювати, видаляти й переставляти правила дзвінків, відкочувати з історії | лише окремою галочкою |
config:export |
вивантаження налаштувань АТС у форматі файлу | лише окремою галочкою |
config:import |
завантаження налаштувань із таблиць: попередній перегляд, потім застосування | лише окремою галочкою |
webhooks:write |
заводити, змінювати, перевіряти й видаляти вебхуки подій дзвінків | лише окремою галочкою |
daynight:write |
закрити точку до кінця доби або до дати, відкрити — те саме, що *28 з телефона |
лише окремою галочкою |
Права, які щось змінюють або витрачають хвилини, у вікні позначені янтарним. Три останніх права не входять до жодного набору, навіть до «Усе» — їх можна дати лише усвідомлено, окремою галочкою.
ChatGPT, claude.ai, Perplexity, Cursor, VS Code: підключення без ключа#
Хмарні асистенти не вміють вставляти ключ у заголовок — вони підключають MCP-сервер через OAuth. Ключ створювати не потрібно.
claude.ai: Налаштування → Конектори → Додати свій конектор → вставте https://api.cenaly.com/pbx-api/mcp → Підключити.
ChatGPT: Налаштування → Додатки та конектори → Додатково → увімкніть режим розробника → Створити → вставте https://api.cenaly.com/pbx-api/mcp, автентифікація — OAuth.
Perplexity: Налаштування облікового запису → Конектори → «+ Свій конектор» → Віддалений → вставте https://api.cenaly.com/pbx-api/mcp, автентифікація — OAuth.
Cursor і VS Code: додайте віддалений (HTTP) MCP-сервер з адресою https://api.cenaly.com/pbx-api/mcp без заголовка з ключем — вікно входу відкриється в браузері. У Cursor: .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}}; у VS Code: команда «MCP: Add Server» → HTTP.
Далі асистент відкриє вікно входу Cenaly. Після входу ви побачите:
- хто просить доступ — додаток називається за адресою, куди повернеться відповідь: «Перевірений конектор · chatgpt.com» (так само — claude.ai, perplexity.ai, vscode.dev, Cursor), «Програма на цьому комп'ютері» або попередження «Незнайома адреса». Назва, яку надіслав додаток, показана дрібно — її може написати будь-хто;
- права — позначено те, що просить додаток (якщо він просить «усе підряд», позначено набір «ШІ-асистент»); права «лише окремою галочкою» заздалегідь не позначаються ніколи;
- точки — усі або вибрані.
«Дозволити» повертає вас до асистента, і він одразу бачить інструменти АТС. Підключення з'являється в Телефонія → API і MCP → Ключі рядком із міткою OAuth та адресою додатка — там само змінюються права й відкликається доступ. Повторне підключення того самого додатка оновлює його права, а не заводить друге підключення.
Дозволяти підключення може лише власник облікового запису.
Claude Code, Claude Desktop, Cursor: підключення за ключем#
Claude Code — однією командою:
claude mcp add --transport http telephony https://api.cenaly.com/pbx-api/mcp --header "Authorization: Bearer cpx_…"
Claude Desktop, Cursor (.cursor/mcp.json) та інші клієнти з файлом налаштувань:
{
"mcpServers": {
"telephony": {
"type": "http",
"url": "https://api.cenaly.com/pbx-api/mcp",
"headers": { "Authorization": "Bearer cpx_…" }
}
}
}
Готові вставки з вашим ключем показуються одразу після створення ключа. ШІ-помічник бачить лише інструменти, дозволені ключем, і може відповісти на «хто сьогодні телефонував і не додзвонився», «передзвони цьому гостю з телефона Анни», «увімкни мені переадресацію на мобільний».
REST API#
Ключ — у заголовку Authorization: Bearer <ключ> (або X-Api-Key). Якщо в ключа одна точка, параметр location можна не передавати; якщо кілька — відповідь 400 location_required перелічить їх.
| Метод | Шлях | Право | Що робить |
|---|---|---|---|
| GET | /v1/me |
— | права, точки та ліміти ключа |
| GET | /v1/locations |
— | точки ключа та їхні АТС |
| GET | /v1/calls |
calls:read |
журнал дзвінків: since, until, direction, status (answered, missed, ai), number, extension, limit до 100, cursor |
| GET | /v1/calls/{id} |
calls:read |
дзвінок із маршрутом: яке правило спрацювало, чий телефон дзвонив, хто відповів |
| GET | /v1/calls/{id}/recording |
recordings:read |
посилання на запис на 10 хвилин |
| GET | /v1/calls/{id}/transcript |
recordings:read |
розшифрування та підсумок розмови |
| POST | /v1/dial |
calls:dial |
дзвінок в один клік: { "extension": "101", "number": "+995555123456" } |
| GET | /v1/dial/{commandId} |
calls:dial |
як проходить дзвінок в один клік |
| GET | /v1/extensions |
extensions:read |
додаткові, групи, переадресація, «не турбувати» |
| PUT | /v1/extensions/{ext}/forwarding |
extensions:write |
особиста переадресація додаткового |
| PUT | /v1/extensions/{ext}/dnd |
extensions:write |
«не турбувати»: { "on": true } |
| GET | /v1/presence |
presence:read |
хто вільний прямо зараз |
| GET | /v1/metrics |
reports:read |
метрики кол-центру за період: from, to (місцеві дати точки YYYY-MM-DD, усталено — останні 7 днів), compare (prev, year, prev,year або порожньо), sections (metrics,loss,queues,lines,operators,directions,heatmap,daily), callbacks=true — ще й швидкість передзвону |
| GET | /v1/routes |
routes:read |
номери, правила вхідних і вихідних |
| GET | /v1/routes/history |
routes:read |
історія змін правил |
| POST, PUT, DELETE | /v1/routes/inbound…, /v1/routes/outbound… |
routes:write |
правила дзвінків по одному: створити, змінити передані поля, видалити, переставити, відкотити |
| GET, POST | /v1/config/export, /v1/config/import |
config:export, config:import |
налаштування у форматі файлу; завантаження — попередній перегляд, потім застосування |
| GET | /v1/events |
calls:read |
події дзвінків точки за 7 днів (до 2000): since (id події або час), types, limit (до 500 за відповідь) |
| GET, POST, PATCH, DELETE | /v1/webhooks… |
webhooks:write |
вебхуки: список, створити, змінити, видалити; …/rotate-secret, …/test, …/deliveries |
| GET, PUT | /v1/open-closed |
routes:read, daynight:write |
чи зачинено і до коли; зачинити до кінця доби { "closed": true }, до дати { "closed": true, "until": "2026-10-05T09:00" } або відчинити |
Повний опис полів — на сторінці документації та в OpenAPI.
Хто сьогодні телефонував і не додзвонився:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/calls?status=missed&since=$(date -u +%Y-%m-%dT00:00:00Z)"
Передзвонити клієнту з телефона додаткового 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"
Метрики за вересень із порівнянням із серпнем і вереснем минулого року — для своєї BI-панелі:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/metrics?from=2026-09-01&to=2026-09-30&compare=prev,year"
У відповіді metrics — ті самі цифри, що на екрані Телефонія → Журнал дзвінків → Аналітика: вхідні, прийняті та пропущені, рівень обслуговування (поріг і мета — з налаштувань черги), середнє та максимальне очікування, частка покинутих без коротких, AHT, FCR, частка переведень і бота, CSAT. compare.prev і compare.year — ті самі поля за минулий період і за той самий період рік тому. Порівняння з минулим роком рахується для періодів до 400 днів.
Увімкнути переадресацію на мобільний, якщо співробітник не відповів за 15 секунд:
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"
Інструменти MCP#
Ті самі операції, що й у REST. Клієнт бачить лише інструменти, дозволені ключем або підключенням:
| Інструменти | Право |
|---|---|
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 |
Сервер працює без сесій (streamable HTTP, JSON-RPC 2.0): initialize, tools/list, tools/call.
OAuth для розробників власних конекторів#
Сервер авторизації відповідає специфікації авторизації MCP — підійде будь-який клієнт, який її підтримує:
- Запит до MCP без токена отримує 401 із заголовком
WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp". - Метадані ресурсу (RFC 9728) називають сервер авторизації —
https://api.cenaly.com/pbx-api; його метадані (RFC 8414) — за адресоюhttps://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api(і…/pbx-api/.well-known/openid-configuration). - Динамічна реєстрація клієнта (RFC 7591):
POST /pbx-api/oauth/register. Адреса повернення — лишеlocalhost/127.0.0.1(будь-який порт) або адреса відомого конектора (claude.ai, claude.com, chatgpt.com, chat.openai.com, vscode.dev, www.perplexity.ai, enterprise.perplexity.ai; у Cursor — ще рівноcursor://anysphere.cursor-mcp/oauth/callback). Спосіб входу клієнта —none(публічний клієнт),client_secret_postабоclient_secret_basic. - Код авторизації з PKCE (лише
S256):GET /pbx-api/oauth/authorize→ вікно входу й згоди власника → повернення на вашу адресу зcode,stateтаiss. Параметрresource— адреса MCP-сервера. - Токени:
POST /pbx-api/oauth/token. Код одноразовий і живе 2 хвилини (невірнийcode_verifierйого гасить); токен доступу — 1 година; токен оновлення — 90 днів, під час кожного оновлення видається новий, попередній перестає працювати. - Відкликання:
POST /pbx-api/oauth/revoke(RFC 7009) гасить підключення цілком — як «Відкликати» у вікні «API і MCP».
Токен доступу приймається всюди, де ключ: і в MCP, і в REST, з правами й точками, які дозволив власник.
Ліміти та помилки#
- На ключ або підключення: 120 запитів за хвилину і 20 000 за добу (REST і MCP разом).
- Дзвінок у клік — окремо: 10 за хвилину і 300 за добу.
- Журнал — до 100 дзвінків за запит; у журналі АТС точки — останні 400 дзвінків за 90 днів.
| Код | Помилка | Що робити |
|---|---|---|
| 401 | api_key_missing, api_key_invalid |
ключа немає, його відкликано або він минув; токен OAuth минув — оновіть його |
| 403 | scope_required |
у ключа немає права — додайте його в «Права» |
| 400 | location_required |
у ключа кілька точок — передайте location |
| 404 | location_not_found |
точки немає або ключ обмежено іншими точками |
| 429 | rate_limited |
ліміт вичерпано, повторіть за Retry-After секунд |
Події дзвінків#
У реальному часі — вебхуки АТС: Телефонія → API і MCP → Вебхуки або POST /v1/webhooks ключем із правом webhooks:write. На вашу https-адресу за секунди надходить POST на кожну подію: call.started (розпочався: напрямок, хто, куди, лінія), call.ringing (у кого дзвонить — по одному на кожен телефон), call.answered (хто відповів), call.transferred (хто і кому перевів), call.ended (підсумок, тривалість, розмова, хто відповів). Вебхук можна обмежити точками та типами подій.
{ "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": "Анна" } } }
Підпис — заголовок X-Cenaly-Signature: t=<час unix>,v1=<HMAC-SHA256 від "t.тіло" секретом вебхука>. Перерахуйте, порівняйте за сталий час і відхиліть t, старший за 5 хвилин. Секрет whsec_… показується один раз; «Новий секрет» гасить попередній одразу.
Доставка — дайте відповідь 2xx за 10 секунд. Інакше повторюємо з паузами 10 с, 30 с, 2, 5, 10, 15 і 15 хвилин (8 спроб, близько години); повтор несе той самий id — за ним відкидайте дублі. Журнал доставок (код відповіді, час, спроба) — у вікні вебхука та GET /v1/webhooks/{id}/deliveries; «Перевірити» надсилає службовий webhook.ping. Адреса 3 доби підряд не прийняла жодної доставки — вебхук вимикається сам: власнику надходить лист, у вікні «Вебхуки» — позначка «Вимкнено автоматично» і кнопка «Увімкнути» (або PATCH /v1/webhooks/{id} з { "enabled": true }).
Без власного сервера — та сама стрічка опитуванням: GET /v1/events?since=<id останньої події> або інструмент MCP get_call_events (події точки за останні 7 днів, до 2000; за відповідь — до 500, more: true — гортайте далі тим самим since).
Після обробки запису — дзвінок із розшифровкою та розбором надходить вебхуком джерела «Вебхук» у розділі «Дзвінки».
«Відкрито / закрито» — PUT /v1/open-closed з { "closed": true } закриває точку до кінця доби (як *28 з телефону: дзвінки йдуть правилами «поза годинами»), false — відкриває; GET показує, чи закрито і ким. З "until" — закрито до цього моменту (не далі 30 днів), потім відкриється само: час без зміщення (2026-10-05T09:00) читається в поясі точки; false знімає і його. Потрібна увімкнена галка «Закрити кодом *28» у маршрутизації (інакше 409).
Безпека#
- Ключ показується один раз і зберігається в нас лише відбитком; ключ, що витік, відкликається однією кнопкою.
- OAuth-підключення дозволяє лише власник, і видно, на яку адресу йде доступ; дозволене підключення можна обмежити правами та точками і відкликати будь-якої миті.
- Номери телефонів — персональні дані ваших клієнтів: давайте права на журнал і записи лише тим інтеграціям, яким вони справді потрібні.
- Усі зміни за ключем або підключенням — у журналі дій АТС із назвою ключа або додатка.