C cenaly.com
Започнете безплатно

API и MCP на собствена телефонна централа

Ключове и права, REST API, MCP сървър за Claude и Cursor, свързване на ChatGPT и claude.ai чрез OAuth без ключ, примери, лимити и грешки

On this page 10

API и MCP на собствената ви АТС

Собствената ви АТС Cenaly е отворена за вашите програми и AI асистенти:

  • 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, AI асистент, само четене, всичко
recordings:read връзка към запис на разговора (10 минути) и транскрипция CRM, AI асистент, само четене, всичко
calls:dial обаждане с едно кликване: първо звъни телефонът на служителя, след отговор АТС набира номера CRM, AI асистент, всичко
extensions:read вътрешни номера, групи, пренасочване, „не безпокойте“ CRM, AI асистент, само четене, всичко
extensions:write промяна на лично пренасочване и „не безпокойте“ AI асистент, всичко
presence:read кой е свободен, звъни, разговаря AI асистент, само четене, всичко
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), „Програма на този компютър“ или предупреждение „Непознат адрес“. Името, което приложението е изпратило, е показано с дребен шрифт — то може да бъде написано от всеки;
  • права — отбелязано е това, което иска приложението (ако иска „всичко подред“, е отбелязан наборът „AI асистент“); правата „само с отделна отметка“ никога не се отбелязват предварително;
  • обекти — всички или избрани.

„Разреши“ ви връща в асистента и той веднага вижда инструментите на АТС. Връзката се появява в Телефония → 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_…" }
    }
  }
}

Готовите фрагменти за вмъкване с вашия ключ се показват веднага след създаването на ключа. AI асистентът вижда само инструментите, разрешени от ключа, и може да отговори на „кой е звънял днес и не се е свързал“, „обади се обратно на този гост от телефона на Анна“, „включи ми пренасочване към мобилния“.

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 — подходящ е всеки клиент, който я поддържа:

  1. Заявка към MCP без токен получава 401 със заглавка WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp".
  2. Метаданните на ресурса (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).
  3. Динамична регистрация на клиента (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.
  4. Код за авторизация с PKCE (само S256): GET /pbx-api/oauth/authorize → прозорец за вход и съгласие на собственика → връщане на вашия адрес с code, state и iss. Параметърът resource е адресът на MCP сървъра.
  5. Токени: POST /pbx-api/oauth/token. Кодът е еднократен и живее 2 минути (грешен code_verifier го погасява); токенът за достъп е 1 час; токенът за обновяване е 90 дни, при всяко обновяване се издава нов, а предишният спира да работи.
  6. Отмяна: 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 връзка разрешава само собственикът и се вижда на кой адрес отива достъпът; разрешената връзка може да бъде ограничена по права и обекти и отменена по всяко време.
  • Телефонните номера са лични данни на вашите клиенти: давайте права за журнала и записите само на интеграциите, на които наистина са нужни.
  • Всички промени по ключ или връзка — в журнала за действия на АТС с името на ключа или приложението.
Was this article helpful?