API i MCP sopstvene centrale
Sopstvena centrala Cenaly otvorena je za vaše programe i AI asistente:
- CRM, računovodstveni sistem, sopstveni sajt — REST API: dnevnik poziva, snimci i transkripti, poziv u klik, interne linije, preusmeravanje, pravila poziva;
- Claude Code, Claude Desktop, Cursor — udaljeni MCP server pomoću ključa;
- ChatGPT, claude.ai, Perplexity, Cursor i VS Code — isti MCP server bez ključa: prijavite se na svoj nalog i odobrite pristup (OAuth).
Sve radi u ime vlasnika naloga i samo sa pravima koja je on dodelio. Svaka izmena je vidljiva u dnevniku radnji centrale sa nazivom ključa ili aplikacije.
Adrese#
| Šta | Adresa |
|---|---|
| REST API | https://api.cenaly.com/pbx-api/v1 |
| MCP server (streamable HTTP) | https://api.cenaly.com/pbx-api/mcp |
| Dokumentacija metoda | api.cenaly.com/pbx-api/v1/docs |
| OpenAPI 3.1 opis | api.cenaly.com/pbx-api/v1/openapi.json |
| OAuth metapodaci | https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api |
Ključ i prava#
Ključ kreira samo vlasnik naloga: Telefonija → API i MCP → Ključevi → Kreiraj ključ. Zaposleni sa ulogom „Administrator centrale“ ne vidi ključeve — ključ deluje u ime vlasnika.
- Ključ oblika
cpx_…prikazuje se samo jednom — odmah nakon kreiranja, zajedno sa gotovim isečcima za povezivanje. Kod nas se čuva samo njegov otisak (SHA-256), ključ nije moguće povratiti — samo izdati novi. - Ključ se može ograničiti lokacijama (inače — sve lokacije, uključujući buduće) i rokom (30, 90, 365 dana ili neograničeno).
- „Prava“ menjaju prava i lokacije ključa u letu: integracija nastavlja da radi, nova prava važe od sledećeg zahteva.
- „Opozovi“ — odmah i zauvek: sledeći zahtev sa tim ključem dobiće 401.
- Aktivnih ključeva i veza — do 20 po nalogu.
Prava se biraju gotovim skupom ili štikliranjem:
| Pravo | Šta daje | Skupovi |
|---|---|---|
calls:read |
dnevnik poziva i kartica poziva sa rutom | CRM, AI asistent, samo čitanje, sve |
recordings:read |
link do snimka razgovora (10 minuta) i transkript | CRM, AI asistent, samo čitanje, sve |
calls:dial |
poziv u klik: prvo zvoni telefon zaposlenog, nakon odgovora centrala bira broj | CRM, AI asistent, sve |
extensions:read |
interne linije, grupe, preusmeravanje, „ne uznemiravaj“ | CRM, AI asistent, samo čitanje, sve |
extensions:write |
menjanje ličnog preusmeravanja i „ne uznemiravaj“ | AI asistent, sve |
presence:read |
ko je slobodan, ko zove, ko razgovara | AI asistent, samo čitanje, sve |
reports:read |
metrike kontakt centra za period: nivo usluge, čekanje, propušteni, AHT, FCR, CSAT, gde gubimo pozive, presek po redovima čekanja, linijama, zaposlenima | samo čitanje, sve |
routes:read |
brojevi, pravila dolaznih i odlaznih poziva, istorija pravila | samo čitanje, sve |
routes:write |
kreiranje, menjanje, brisanje i premeštanje pravila poziva, vraćanje iz istorije | samo posebnom štiklom |
config:export |
izvoz podešavanja centrale u formatu datoteke | samo posebnom štiklom |
config:import |
uvoz podešavanja iz tabela: pregled, zatim primena | samo posebnom štiklom |
webhooks:write |
postavljanje, menjanje, provera i brisanje vebhukova događaja poziva | samo posebnom štiklom |
daynight:write |
zatvaranje lokacije do kraja dana ili do datuma, otvaranje — isto što i *28 sa telefona |
samo posebnom štiklom |
Prava koja nešto menjaju ili troše minute označena su u prozoru ćilibarskom bojom. Poslednja tri prava ne ulaze ni u jedan skup, čak ni u „Sve“ — mogu se dodeliti samo svesno, posebnom štiklom.
ChatGPT, claude.ai, Perplexity, Cursor, VS Code: povezivanje bez ključa#
Cloud asistenti ne umeju da ubace ključ u zaglavlje — oni povezuju MCP server putem OAuth. Ključ nije potrebno kreirati.
claude.ai: Podešavanja → Konektori → Dodaj sopstveni konektor → nalepite https://api.cenaly.com/pbx-api/mcp → Poveži.
ChatGPT: Podešavanja → Aplikacije i konektori → Napredno → uključite režim za programere → Kreiraj → nalepite https://api.cenaly.com/pbx-api/mcp, autentifikacija — OAuth.
Perplexity: Podešavanja naloga → Konektori → „+ Sopstveni konektor“ → Udaljeni → nalepite https://api.cenaly.com/pbx-api/mcp, autentifikacija — OAuth.
Cursor i VS Code: dodajte udaljeni (HTTP) MCP server sa adresom https://api.cenaly.com/pbx-api/mcp bez zaglavlja sa ključem — prozor za prijavu otvoriće se u pregledaču. U Cursor-u: .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}}; u VS Code-u: komanda „MCP: Add Server“ → HTTP.
Zatim će asistent otvoriti prozor za prijavu na Cenaly. Nakon prijave videćete:
- ko traži pristup — aplikacija se imenuje po adresi na koju će se vratiti odgovor: „Provereni konektor · chatgpt.com“ (isto — claude.ai, perplexity.ai, vscode.dev, Cursor), „Program na ovom računaru“ ili upozorenje „Nepoznata adresa“. Naziv koji je aplikacija poslala prikazan je sitno — može ga napisati bilo ko;
- prava — označeno je ono što aplikacija traži (ako traži „sve redom“, označen je skup „AI asistent“); prava „samo posebnom štiklom“ nikada se ne označavaju unapred;
- lokacije — sve ili izabrane.
„Dozvoli“ vas vraća u asistenta i on odmah vidi alate centrale. Veza se pojavljuje u Telefonija → API i MCP → Ključevi kao red sa oznakom OAuth i adresom aplikacije — tu se menjaju prava i opoziva pristup. Ponovno povezivanje iste aplikacije ažurira njena prava, a ne otvara drugu vezu.
Veze može da odobrava samo vlasnik naloga.
Claude Code, Claude Desktop, Cursor: povezivanje pomoću ključa#
Claude Code — jednom komandom:
claude mcp add --transport http telephony https://api.cenaly.com/pbx-api/mcp --header "Authorization: Bearer cpx_…"
Claude Desktop, Cursor (.cursor/mcp.json) i drugi klijenti sa datotekom podešavanja:
{
"mcpServers": {
"telephony": {
"type": "http",
"url": "https://api.cenaly.com/pbx-api/mcp",
"headers": { "Authorization": "Bearer cpx_…" }
}
}
}
Gotovi isečci sa vašim ključem prikazuju se odmah nakon kreiranja ključa. Asistent vidi samo alate koje ključ dozvoljava i može da odgovori na „ko je danas zvao i nije se javio“, „pozovi ovog gosta sa telefona Ane“, „uključi mi preusmeravanje na mobilni“.
REST API#
Ključ — u zaglavlju Authorization: Bearer <ključ> (ili X-Api-Key). Ako ključ ima jednu lokaciju, parametar location ne mora da se prosledi; ako ima više — odgovor 400 location_required će ih navesti.
| Metod | Putanja | Pravo | Šta radi |
|---|---|---|---|
| GET | /v1/me |
— | prava, lokacije i limiti ključa |
| GET | /v1/locations |
— | lokacije ključa i njihove telefonske centrale |
| GET | /v1/calls |
calls:read |
dnevnik poziva: since, until, direction, status (answered, missed, ai), number, extension, limit do 100, cursor |
| GET | /v1/calls/{id} |
calls:read |
poziv sa rutom: koje pravilo se aktiviralo, čiji je telefon zvonio, ko se javio |
| GET | /v1/calls/{id}/recording |
recordings:read |
link do snimka na 10 minuta |
| GET | /v1/calls/{id}/transcript |
recordings:read |
transkript i sažetak razgovora |
| POST | /v1/dial |
calls:dial |
poziv jednim klikom: { "extension": "101", "number": "+995555123456" } |
| GET | /v1/dial/{commandId} |
calls:dial |
kako teče poziv jednim klikom |
| GET | /v1/extensions |
extensions:read |
ekstenzije, grupe, preusmeravanje, „ne uznemiravaj“ |
| PUT | /v1/extensions/{ext}/forwarding |
extensions:write |
lično preusmeravanje ekstenzije |
| PUT | /v1/extensions/{ext}/dnd |
extensions:write |
„ne uznemiravaj“: { "on": true } |
| GET | /v1/presence |
presence:read |
ko je slobodan upravo sada |
| GET | /v1/metrics |
reports:read |
metrike kontakt centra za period: from, to (lokalni datumi lokacije YYYY-MM-DD, podrazumevano — poslednjih 7 dana), compare (prev, year, prev,year ili prazno), sections (metrics,loss,queues,lines,operators,directions,heatmap,daily), callbacks=true — i brzina povratnog poziva |
| GET | /v1/routes |
routes:read |
brojevi, pravila dolaznih i odlaznih poziva |
| GET | /v1/routes/history |
routes:read |
istorija izmena pravila |
| POST, PUT, DELETE | /v1/routes/inbound…, /v1/routes/outbound… |
routes:write |
pravila poziva pojedinačno: kreirati, izmeniti prosleđena polja, obrisati, premestiti, vratiti |
| GET, POST | /v1/config/export, /v1/config/import |
config:export, config:import |
podešavanja u formatu datoteke; učitavanje — pregled, zatim primena |
| GET | /v1/events |
calls:read |
događaji poziva lokacije za 7 dana (do 2000): since (id događaja ili vreme), types, limit (do 500 po odgovoru) |
| GET, POST, PATCH, DELETE | /v1/webhooks… |
webhooks:write |
vebhukovi: lista, kreiranje, izmena, brisanje; …/rotate-secret, …/test, …/deliveries |
| GET, PUT | /v1/open-closed |
routes:read, daynight:write |
da li je zatvoreno i do kada; zatvoriti do kraja dana { "closed": true }, do datuma { "closed": true, "until": "2026-10-05T09:00" } ili otvoriti |
Potpuni opis polja — na stranici dokumentacije i u OpenAPI.
Ko je danas zvao i nije se javio:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/calls?status=missed&since=$(date -u +%Y-%m-%dT00:00:00Z)"
Povratni poziv klijentu sa telefona ekstenzije 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"
Metrike za septembar sa poređenjem sa avgustom i septembrom prošle godine — za sopstveni BI panel:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/metrics?from=2026-09-01&to=2026-09-30&compare=prev,year"
U odgovoru metrics — iste brojke kao na ekranu Telefonija → Dnevnik poziva → Analitika: dolazni, prihvaćeni i propušteni, nivo usluge (prag i cilj — iz podešavanja reda), prosečno i maksimalno čekanje, udeo napuštenih bez kratkih, AHT, FCR, udeo transfera i bota, CSAT. compare.prev i compare.year — ista polja za prethodni period i za isti period pre godinu dana. Poređenje sa prošlom godinom računa se za periode do 400 dana.
Uključiti preusmeravanje na mobilni, ako se zaposleni ne javi za 15 sekundi:
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 alatke#
Iste operacije kao kod REST-a. Klijent vidi samo alatke koje su dozvoljene ključem ili povezivanjem:
| Alatke | Pravo |
|---|---|
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 radi bez sesija (streamable HTTP, JSON-RPC 2.0): initialize, tools/list, tools/call.
OAuth za programere sopstvenih konektora#
Server za autorizaciju prati specifikaciju autorizacije MCP — odgovaraće svaki klijent koji je podržava:
- Zahtev ka MCP-u bez tokena dobija 401 sa zaglavljem
WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp". - Metapodaci resursa (RFC 9728) navode server za autorizaciju —
https://api.cenaly.com/pbx-api; njegovi metapodaci (RFC 8414) — na adresihttps://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api(i…/pbx-api/.well-known/openid-configuration). - Dinamička registracija klijenta (RFC 7591):
POST /pbx-api/oauth/register. Adresa za povratak — samolocalhost/127.0.0.1(bilo koji port) ili adresa poznatog konektora (claude.ai, claude.com, chatgpt.com, chat.openai.com, vscode.dev, www.perplexity.ai, enterprise.perplexity.ai; kod Cursor-a — još tačnocursor://anysphere.cursor-mcp/oauth/callback). Način prijave klijenta —none(javni klijent),client_secret_postiliclient_secret_basic. - Kod za autorizaciju sa PKCE (samo
S256):GET /pbx-api/oauth/authorize→ prozor za prijavu i saglasnost vlasnika → povratak na vašu adresu sacode,stateiiss. Parametarresource— adresa MCP servera. - Tokeni:
POST /pbx-api/oauth/token. Kod je jednokratan i živi 2 minuta (pogrešancode_verifierga gasi); token za pristup — 1 sat; token za obnavljanje — 90 dana, pri svakom obnavljanju izdaje se novi, prethodni prestaje da radi. - Opoziv:
POST /pbx-api/oauth/revoke(RFC 7009) gasi povezivanje u celini — kao „Opozovi“ u prozoru „API i MCP“.
Token za pristup se prihvata svuda gde i ključ: i u MCP-u, i u REST-u, sa pravima i lokacijama koje je vlasnik dozvolio.
Limiti i greške#
- Na ključ ili povezivanje: 120 zahteva u minuti i 20 000 dnevno (REST i MCP zajedno).
- Poziv u klik — odvojeno: 10 u minuti i 300 dnevno.
- Dnevnik — do 100 poziva po zahtevu; u dnevniku PBX-a lokacije — poslednjih 400 poziva za 90 dana.
| Kod | Greška | Šta učiniti |
|---|---|---|
| 401 | api_key_missing, api_key_invalid |
ključa nema, opozvan je ili je istekao; OAuth token je istekao — obnovite ga |
| 403 | scope_required |
ključ nema pravo — dodajte ga u „Prava“ |
| 400 | location_required |
ključ ima više lokacija — prosledite location |
| 404 | location_not_found |
lokacije nema ili je ključ ograničen na druge lokacije |
| 429 | rate_limited |
limit je iscrpljen, pokušajte ponovo za Retry-After sekundi |
Događaji poziva#
U realnom vremenu — vebhukovi telefonske centrale: Telefonija → API i MCP → Vebhukovi ili POST /v1/webhooks ključem sa pravom webhooks:write. Na vašu https-adresu za nekoliko sekundi stiže POST za svaki događaj: call.started (počeo: smer, ko, kome, linija), call.ringing (kome zvoni — po jedan za svaki telefon), call.answered (ko se javio), call.transferred (ko je i kome preusmerio), call.ended (ishod, trajanje, razgovor, ko se javio). Vebhuk možete ograničiti na lokacije i tipove događaja.
{ "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": "Анна" } } }
Potpis — zaglavlje X-Cenaly-Signature: t=<vreme unix>,v1=<HMAC-SHA256 od "t.telo" tajnom vebhuka>. Preračunajte, uporedite u konstantnom vremenu i odbijte t stariji od 5 minuta. Tajna whsec_… prikazuje se jednom; „Nova tajna“ odmah gasi prethodnu.
Isporuka — odgovorite 2xx u roku od 10 sekundi. U suprotnom ponavljamo sa pauzama od 10 s, 30 s, 2, 5, 10, 15 i 15 minuta (8 pokušaja, oko sat vremena); ponavljanje nosi isti id — po njemu odbacujte duplikate. Dnevnik isporuka (kod odgovora, vreme, pokušaj) — u prozoru vebhuka i GET /v1/webhooks/{id}/deliveries; „Proveri“ šalje servisni webhook.ping. Ako adresa 3 dana zaredom nije primila nijednu isporuku — vebhuk se sam isključuje: vlasniku stiže imejl, u prozoru „Vebhukovi“ — oznaka „Automatski isključen“ i dugme „Uključi“ (ili PATCH /v1/webhooks/{id} sa { "enabled": true }).
Bez sopstvenog servera — isti tok anketiranjem: GET /v1/events?since=<id poslednjeg događaja> ili MCP alat get_call_events (događaji lokacije za poslednjih 7 dana, do 2000; po odgovoru — do 500, more: true — listajte dalje istim since).
Posle obrade snimka — poziv sa transkriptom i analizom stiže vebhukom izvora „Vebhuk“ u odeljku „Pozivi“.
„Otvoreno / zatvoreno“ — PUT /v1/open-closed sa { "closed": true } zatvara lokaciju do kraja dana (kao *28 sa telefona: pozivi idu pravilima „van radnog vremena“), false — otvara; GET pokazuje da li je zatvoreno i ko je zatvorio. Sa "until" — zatvoreno do tog trenutka (ne dalje od 30 dana), pa se samo otvori: vreme bez pomeranja (2026-10-05T09:00) čita se u vremenskoj zoni lokacije; false poništava i njega. Potrebna je uključena kvačica „Zatvori kodom *28“ u rutiranju (inače 409).
Bezbednost#
- Ključ se prikazuje jednom i kod nas se čuva samo kao otisak; procureli ključ se opoziva jednim dugmetom.
- OAuth vezu odobrava samo vlasnik, i vidi se kojoj adresi odlazi pristup; odobrena veza može se ograničiti pravima i lokacijama i opozvati u svakom trenutku.
- Brojevi telefona su lični podaci vaših klijenata: dajte prava na dnevnik i snimke samo onim integracijama kojima su zaista potrebna.
- Sve izmene po ključu ili vezi — u dnevniku radnji telefonske centrale sa nazivom ključa ili aplikacije.