C cenaly.com
무료로 시작하기

자체 PBX용 API 및 MCP

키 및 권한, REST API, Claude 및 Cursor용 MCP 서버, 키 없는 OAuth 기반 ChatGPT 및 claude.ai 연동, 예제, 한도 및 오류

10 min read 관리자 페이지 데모
On this page 10

자체 PBX의 API 및 MCP

자체 PBX Cenaly는 여러분의 프로그램과 AI 어시스턴트에 열려 있습니다:

  • CRM, 회계 시스템, 자체 웹사이트 — REST API: 통화 기록, 녹음 및 녹취록, 클릭 투 콜, 내선, 착신 전환, 통화 규칙;
  • Claude Code, Claude Desktop, Cursor — 키로 연결하는 원격 MCP 서버;
  • ChatGPT, claude.ai, Perplexity, Cursor 및 VS Code — 동일한 MCP 서버를 키 없이 사용: 본인 계정에 로그인하고 접근을 허용합니다(OAuth).

모든 것은 계정 소유자 명의로, 소유자가 부여한 권한 내에서만 작동합니다. 모든 변경 사항은 키 또는 앱 이름과 함께 PBX 작업 로그에 표시됩니다.

주소#

항목 주소
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 → 키 → 키 생성. "PBX 관리자" 역할의 직원은 키를 볼 수 없습니다 — 키는 소유자 명의로 작동합니다.

  • cpx_… 형식의 키는 생성 직후 한 번만 표시되며, 연결용으로 준비된 코드 조각과 함께 제공됩니다. 당사에는 키의 지문(SHA-256)만 저장되므로 키를 복원할 수 없으며, 새로 발급하는 것만 가능합니다.
  • 키는 지점(지정하지 않으면 향후 생성될 지점을 포함한 모든 지점)과 기간(30일, 90일, 365일 또는 무기한)으로 제한할 수 있습니다.
  • **"권한"**은 키의 권한과 지점을 즉시 변경합니다: 통합은 계속 작동하며, 새 권한은 다음 요청부터 적용됩니다.
  • **"폐기"**는 즉시 그리고 영구적으로 적용됩니다: 해당 키를 사용한 다음 요청은 401을 받습니다.
  • 계정당 활성 키 및 연결은 최대 20개입니다.

권한은 미리 준비된 세트 또는 개별 체크박스로 선택합니다:

권한 제공 내용 세트
calls:read 통화 기록 및 경로가 포함된 통화 카드 CRM, AI 어시스턴트, 읽기 전용, 전체
recordings:read 통화 녹음 링크(10분) 및 녹취록 CRM, AI 어시스턴트, 읽기 전용, 전체
calls:dial 클릭 투 콜: 먼저 직원의 전화가 울리고, 응답 후 PBX가 번호를 다이얼합니다 CRM, AI 어시스턴트, 전체
extensions:read 내선, 그룹, 착신 전환, "방해 금지" CRM, AI 어시스턴트, 읽기 전용, 전체
extensions:write 개인 착신 전환 및 "방해 금지" 변경 AI 어시스턴트, 전체
presence:read 누가 통화 가능한지, 통화 중인지, 통화하고 있는지 AI 어시스턴트, 읽기 전용, 전체
reports:read 기간별 콜센터 지표: 서비스 수준, 대기, 포기, AHT, FCR, CSAT, 통화 손실 지점, 대기열·회선·직원별 분석 읽기 전용, 전체
routes:read 번호, 인바운드 및 아웃바운드 규칙, 규칙 이력 읽기 전용, 전체
routes:write 통화 규칙 생성, 변경, 삭제, 순서 변경, 이력에서 복원 별도 체크박스만
config:export PBX 설정을 파일 형식으로 내보내기 별도 체크박스만
config:import 테이블에서 설정 가져오기: 미리보기 후 적용 별도 체크박스만
webhooks:write 통화 이벤트 웹훅 생성, 변경, 테스트, 삭제 별도 체크박스만
daynight:write 지점을 당일 종료 시까지 또는 특정 날짜까지 닫기, 열기 — 전화기의 *28과 동일 별도 체크박스만

무언가를 변경하거나 통화 시간을 소모하는 권한은 창에서 황색으로 표시됩니다. 마지막 세 권한은 "전체"를 포함한 어떤 세트에도 포함되지 않습니다 — 별도 체크박스로만 의식적으로 부여할 수 있습니다.

ChatGPT, claude.ai, Perplexity, Cursor, VS Code: 키 없이 연결#

클라우드 어시스턴트는 헤더에 키를 삽입할 수 없으므로 OAuth로 MCP 서버를 연결합니다. 키를 생성할 필요가 없습니다.

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: 키 헤더 없이 https://api.cenaly.com/pbx-api/mcp 주소로 원격(HTTP) 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 어시스턴트" 세트가 표시됨); "별도 체크박스만" 권한은 사전에 절대 표시되지 않습니다;
  • 지점 — 전체 또는 선택.

"허용"을 누르면 어시스턴트로 돌아가며, 어시스턴트는 즉시 PBX 도구를 볼 수 있습니다. 연결은 텔레포니 → 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 — 키의 지점과 각 지점의 PBX
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"

9월 지표를 8월 및 작년 9월과 비교 — 자체 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에 요청하면 WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp" 헤더와 함께 401을 받습니다.
  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통화; PBX의 지점 로그에는 최근 90일간의 최근 400통화가 표시됩니다.
코드 오류 해결 방법
401 api_key_missing, api_key_invalid 키가 없거나, 철회되었거나, 만료되었습니다; OAuth 토큰이 만료되었으면 갱신하십시오
403 scope_required 키에 권한이 없습니다 — “권한”에서 추가하십시오
400 location_required 키에 지점이 여러 개 있습니다 — location을 전달하십시오
404 location_not_found 지점이 없거나 키가 다른 지점으로 제한되어 있습니다
429 rate_limited 한도가 소진되었습니다. Retry-After초 후에 다시 시도하십시오

통화 이벤트#

실시간 — PBX 웹훅: 텔레포니 → API 및 MCP → 웹훅 또는 webhooks:write 권한이 있는 키로 POST /v1/webhooks. 귀하의 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=<"t.본문"에 대한 HMAC-SHA256, 웹훅 시크릿 사용>. 재계산하고, 상수 시간으로 비교하며, 5분보다 오래된 t는 거부합니다. 시크릿 whsec_…은 한 번만 표시되며, "새 시크릿"은 이전 시크릿을 즉시 무효화합니다.

전달 — 10초 이내에 2xx로 응답합니다. 그렇지 않으면 10초, 30초, 2, 5, 10, 15, 15분 간격으로 재시도합니다 (8회 시도, 약 1시간). 재시도는 동일한 id를 가지므로 이를 기준으로 중복을 걸러냅니다. 전달 로그 (응답 코드, 시간, 시도) — 웹훅 창과 GET /v1/webhooks/{id}/deliveries에서 확인할 수 있으며, "확인"은 서비스 webhook.ping을 전송합니다. 주소가 3일 연속 단 하나의 전달도 받지 못하면 웹훅이 자동으로 꺼집니다: 소유자에게 이메일이 발송되고, "웹훅" 창에 "자동으로 꺼짐" 표시와 "켜기" 버튼이 나타납니다 (또는 { "enabled": true }와 함께 PATCH /v1/webhooks/{id}).

자체 서버 없이 — 동일한 피드를 폴링으로: GET /v1/events?since=<마지막 이벤트 id> 또는 MCP 도구 get_call_events (지점의 최근 7일 이벤트, 최대 2000건, 응답당 최대 500건, more: true이면 동일한 since로 계속 조회).

녹음 처리 후 — 녹취 및 분석이 포함된 통화는 “통화” 섹션의 “웹훅” 소스 웹훅으로 도착합니다.

“열림 / 닫힘” — { "closed": true }와 함께 PUT /v1/open-closed를 호출하면 지점이 당일 자정까지 닫힙니다 (전화기의 *28과 동일: 통화는 “운영 시간 외” 규칙으로 처리됨), false는 엽니다. GET은 닫혔는지, 누가 닫았는지 보여줍니다. "until"을 사용하면 해당 시점까지 닫히며 (최대 30일 이내), 이후 자동으로 열립니다: 오프셋 없는 시간 (2026-10-05T09:00)은 지점의 시간대로 해석됩니다. false는 이것도 해제합니다. 라우팅에서 “*28 코드로 닫기” 체크박스가 활성화되어 있어야 합니다 (그렇지 않으면 409).

보안#

  • 키는 한 번만 표시되며, 당사에는 지문만 저장됩니다. 유출된 키는 버튼 하나로 폐기할 수 있습니다.
  • OAuth 연결은 소유자만 승인할 수 있으며, 어느 주소로 접근 권한이 부여되는지 확인할 수 있습니다. 승인된 연결은 권한과 지점으로 제한할 수 있고 언제든지 취소할 수 있습니다.
  • 전화번호는 귀하 고객의 개인정보입니다: 통화 기록과 녹음에 대한 권한은 실제로 필요한 통합에만 부여하십시오.
  • 키 또는 연결을 통한 모든 변경 사항은 키 또는 앱 이름과 함께 PBX 작업 로그에 기록됩니다.
Was this article helpful?