C cenaly.com
Começar grátis

API e MCP do seu PABX

Chaves e permissões, REST API, servidor MCP para Claude e Cursor, conexão do ChatGPT e claude.ai via OAuth sem chave, exemplos, limites e erros

On this page 10

API e MCP da sua central telefônica

Sua central telefônica Cenaly está aberta para seus programas e assistentes de IA:

  • CRM, sistema de gestão, seu site — REST API: histórico de chamadas, gravações e transcrições, chamada com um clique, ramais, encaminhamento, regras de chamadas;
  • Claude Code, Claude Desktop, Cursor — servidor MCP remoto por chave;
  • ChatGPT, claude.ai, Perplexity, Cursor e VS Code — o mesmo servidor MCP sem chave: você entra na sua conta e autoriza o acesso (OAuth).

Tudo funciona em nome do proprietário da conta e apenas com as permissões que ele concedeu. Cada alteração aparece no histórico de ações da central telefônica com o nome da chave ou do aplicativo.

Endereços#

O quê Endereço
REST API https://api.cenaly.com/pbx-api/v1
Servidor MCP (streamable HTTP) https://api.cenaly.com/pbx-api/mcp
Documentação dos métodos api.cenaly.com/pbx-api/v1/docs
Descrição OpenAPI 3.1 api.cenaly.com/pbx-api/v1/openapi.json
Metadados OAuth https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api

Chave e permissões#

A chave é criada apenas pelo proprietário da conta: Telefonia → API e MCP → Chaves → Criar chave. Um colaborador com a função "Administrador da central telefônica" não vê as chaves — a chave funciona em nome do proprietário.

  • A chave no formato cpx_… é exibida uma única vez — logo após a criação, junto com os trechos prontos para conexão. Guardamos apenas a impressão digital dela (SHA-256); não é possível recuperar a chave — só emitir uma nova.
  • A chave pode ser limitada por unidades (caso contrário — todas as unidades, incluindo as futuras) e por prazo (30, 90, 365 dias ou sem prazo).
  • "Permissões" alteram as permissões e as unidades da chave na hora: a integração continua funcionando, e as novas permissões passam a valer a partir da próxima requisição.
  • "Revogar" — imediato e definitivo: a próxima requisição com essa chave receberá 401.
  • Chaves e conexões ativas — até 20 por conta.

As permissões são escolhidas por conjunto pronto ou por caixas de seleção:

Permissão O que concede Conjuntos
calls:read histórico de chamadas e ficha da chamada com rota CRM, assistente de IA, somente leitura, tudo
recordings:read link para a gravação da conversa (10 minutos) e transcrição CRM, assistente de IA, somente leitura, tudo
calls:dial chamada com um clique: primeiro toca o telefone do colaborador, e após o atendimento a central telefônica disca o número CRM, assistente de IA, tudo
extensions:read ramais, grupos, encaminhamento, "não perturbe" CRM, assistente de IA, somente leitura, tudo
extensions:write alterar o encaminhamento pessoal e o "não perturbe" assistente de IA, tudo
presence:read quem está livre, em chamada, falando assistente de IA, somente leitura, tudo
reports:read métricas do call center por período: nível de atendimento, espera, abandonadas, AHT, FCR, CSAT, onde perdemos chamadas, recortes por filas, linhas, colaboradores somente leitura, tudo
routes:read números, regras de entrada e saída, histórico de regras somente leitura, tudo
routes:write criar, alterar, excluir e reordenar regras de chamadas, restaurar do histórico apenas por caixa de seleção separada
config:export exportação das configurações da central telefônica em formato de arquivo apenas por caixa de seleção separada
config:import importação das configurações a partir de tabelas: pré-visualização e depois aplicação apenas por caixa de seleção separada
webhooks:write criar, alterar, testar e excluir webhooks de eventos de chamadas apenas por caixa de seleção separada
daynight:write fechar a unidade até o fim do dia ou até uma data, abrir — o mesmo que *28 pelo telefone apenas por caixa de seleção separada

As permissões que alteram algo ou consomem minutos estão marcadas em âmbar na janela. As três últimas permissões não fazem parte de nenhum conjunto, nem mesmo de "Tudo" — só podem ser concedidas conscientemente, por caixa de seleção separada.

ChatGPT, claude.ai, Perplexity, Cursor, VS Code: conexão sem chave#

Os assistentes na nuvem não conseguem inserir uma chave no cabeçalho — eles conectam o servidor MCP por OAuth. Não é preciso criar uma chave.

claude.ai: Configurações → Conectores → Adicionar seu conector → cole https://api.cenaly.com/pbx-api/mcp → Conectar.

ChatGPT: Configurações → Aplicativos e conectores → Avançado → ative o modo desenvolvedor → Criar → cole https://api.cenaly.com/pbx-api/mcp, autenticação — OAuth.

Perplexity: Configurações da conta → Conectores → "+ Seu conector" → Remoto → cole https://api.cenaly.com/pbx-api/mcp, autenticação — OAuth.

Cursor e VS Code: adicione um servidor MCP remoto (HTTP) com o endereço https://api.cenaly.com/pbx-api/mcp sem cabeçalho com chave — a janela de login abrirá no navegador. No Cursor: .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}}; no VS Code: comando "MCP: Add Server" → HTTP.

Em seguida, o assistente abrirá a janela de login da Cenaly. Após entrar, você verá:

  • quem está pedindo acesso — o aplicativo é nomeado pelo endereço para onde a resposta retornará: "Conector verificado · chatgpt.com" (o mesmo vale para claude.ai, perplexity.ai, vscode.dev, Cursor), "Programa neste computador" ou o aviso "Endereço desconhecido". O nome enviado pelo aplicativo é exibido em letras pequenas — qualquer um pode escrevê-lo;
  • permissões — está marcado o que o aplicativo pede (se ele pede "tudo", o conjunto "Assistente de IA" fica marcado); as permissões "apenas por caixa de seleção separada" nunca são marcadas de antemão;
  • unidades — todas ou as selecionadas.

"Permitir" retorna você ao assistente, e ele passa a ver imediatamente as ferramentas da central telefônica. A conexão aparece em Telefonia → API e MCP → Chaves como uma linha com a etiqueta OAuth e o endereço do aplicativo — é ali também que as permissões são alteradas e o acesso é revogado. Reconectar o mesmo aplicativo atualiza suas permissões, em vez de criar uma segunda conexão.

Somente o proprietário da conta pode autorizar conexões.

Claude Code, Claude Desktop, Cursor: conexão por chave#

Claude Code — com um único comando:

claude mcp add --transport http telephony https://api.cenaly.com/pbx-api/mcp --header "Authorization: Bearer cpx_…"

Claude Desktop, Cursor (.cursor/mcp.json) e outros clientes com arquivo de configurações:

{
  "mcpServers": {
    "telephony": {
      "type": "http",
      "url": "https://api.cenaly.com/pbx-api/mcp",
      "headers": { "Authorization": "Bearer cpx_…" }
    }
  }
}

Os trechos prontos para colar com a sua chave são exibidos logo após a criação da chave. O Assistente de IA vê apenas as ferramentas permitidas pela chave e pode responder a "quem ligou hoje e não foi atendido", "ligue de volta para este cliente do telefone da Anna", "ative para mim o encaminhamento para o celular".

REST API#

A chave vai no cabeçalho Authorization: Bearer <chave> (ou X-Api-Key). Se a chave tiver uma única unidade, o parâmetro location pode ser omitido; se tiver várias, a resposta 400 location_required vai listá-las.

Método Caminho Permissão O que faz
GET /v1/me — permissões, unidades e limites da chave
GET /v1/locations — unidades da chave e suas centrais telefônicas
GET /v1/calls calls:read histórico de chamadas: since, until, direction, status (answered, missed, ai), number, extension, limit até 100, cursor
GET /v1/calls/{id} calls:read chamada com o percurso: qual regra foi acionada, qual telefone tocou, quem atendeu
GET /v1/calls/{id}/recording recordings:read link para a gravação por 10 minutos
GET /v1/calls/{id}/transcript recordings:read transcrição e resumo da conversa
POST /v1/dial calls:dial chamada com um clique: { "extension": "101", "number": "+995555123456" }
GET /v1/dial/{commandId} calls:dial como está a chamada com um clique
GET /v1/extensions extensions:read ramais, grupos, encaminhamento, "não perturbe"
PUT /v1/extensions/{ext}/forwarding extensions:write encaminhamento pessoal do ramal
PUT /v1/extensions/{ext}/dnd extensions:write "não perturbe": { "on": true }
GET /v1/presence presence:read quem está livre agora
GET /v1/metrics reports:read métricas do call center por período: from, to (datas locais da unidade YYYY-MM-DD, padrão — últimos 7 dias), compare (prev, year, prev,year ou vazio), sections (metrics,loss,queues,lines,operators,directions,heatmap,daily), callbacks=true — também a velocidade de retorno de chamada
GET /v1/routes routes:read números, regras de entrada e de saída
GET /v1/routes/history routes:read histórico de alterações das regras
POST, PUT, DELETE /v1/routes/inbound…, /v1/routes/outbound… routes:write regras de chamadas uma a uma: criar, alterar os campos enviados, excluir, reordenar, reverter
GET, POST /v1/config/export, /v1/config/import config:export, config:import configurações em formato de arquivo; o upload — pré-visualização e depois aplicação
GET /v1/events calls:read eventos de chamadas da unidade nos últimos 7 dias (até 2000): since (id do evento ou horário), types, limit (até 500 por resposta)
GET, POST, PATCH, DELETE /v1/webhooks… webhooks:write webhooks: listar, criar, alterar, excluir; …/rotate-secret, …/test, …/deliveries
GET, PUT /v1/open-closed routes:read, daynight:write se está fechado e até quando; fechar até o fim do dia { "closed": true }, até uma data { "closed": true, "until": "2026-10-05T09:00" } ou abrir

A descrição completa dos campos está na página de documentação e no OpenAPI.

Quem ligou hoje e não foi atendido:

curl -H "Authorization: Bearer cpx_…" \
  "https://api.cenaly.com/pbx-api/v1/calls?status=missed&since=$(date -u +%Y-%m-%dT00:00:00Z)"

Ligar de volta para o cliente do telefone do ramal 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"

Métricas de setembro com comparação com agosto e com setembro do ano passado — para o seu painel de 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"

Na resposta, metrics traz os mesmos números que na tela Telefonia → Histórico de chamadas → Análise: chamadas recebidas, atendidas e perdidas, nível de atendimento (limite e meta — das configurações da fila), espera média e máxima, proporção de abandonadas sem chamadas curtas, AHT, FCR, proporção de transferências e de bot, CSAT. compare.prev e compare.year — os mesmos campos do período anterior e do mesmo período um ano atrás. A comparação com o ano passado é calculada para períodos de até 400 dias.

Ativar o encaminhamento para o celular se o funcionário não atender em 15 segundos:

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"

Ferramentas MCP#

As mesmas operações do REST. O cliente vê apenas as ferramentas permitidas pela chave ou pela conexão:

Ferramentas Permissão
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

O servidor funciona sem sessões (streamable HTTP, JSON-RPC 2.0): initialize, tools/list, tools/call.

OAuth para desenvolvedores dos próprios conectores#

O servidor de autorização segue a especificação de autorização MCP — qualquer cliente que a suporte serve:

  1. Uma requisição ao MCP sem token recebe 401 com o cabeçalho WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp".
  2. Os metadados do recurso (RFC 9728) indicam o servidor de autorização — https://api.cenaly.com/pbx-api; os metadados dele (RFC 8414) ficam em https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api (e …/pbx-api/.well-known/openid-configuration).
  3. Registro dinâmico do cliente (RFC 7591): POST /pbx-api/oauth/register. O endereço de retorno é apenas localhost / 127.0.0.1 (qualquer porta) ou o endereço de um conector conhecido (claude.ai, claude.com, chatgpt.com, chat.openai.com, vscode.dev, www.perplexity.ai, enterprise.perplexity.ai; no Cursor — ainda exatamente cursor://anysphere.cursor-mcp/oauth/callback). O método de entrada do cliente é none (cliente público), client_secret_post ou client_secret_basic.
  4. Código de autorização com PKCE (apenas S256): GET /pbx-api/oauth/authorize → janela de entrada e consentimento do proprietário → retorno ao seu endereço com code, state e iss. O parâmetro resource é o endereço do servidor MCP.
  5. Tokens: POST /pbx-api/oauth/token. O código é de uso único e dura 2 minutos (um code_verifier incorreto o invalida); o token de acesso dura 1 hora; o token de atualização dura 90 dias, a cada atualização é emitido um novo e o anterior deixa de funcionar.
  6. Revogação: POST /pbx-api/oauth/revoke (RFC 7009) encerra a conexão por completo — como “Revogar” na janela “API e MCP”.

O token de acesso é aceito em todos os lugares onde a chave é: tanto no MCP quanto no REST, com as permissões e unidades que o proprietário autorizou.

Limites e erros#

  • Por chave ou conexão: 120 requisições por minuto e 20 000 por dia (REST e MCP juntos).
  • Chamada em um clique — separadamente: 10 por minuto e 300 por dia.
  • O histórico — até 100 chamadas por requisição; no histórico da central telefônica da unidade — as últimas 400 chamadas em 90 dias.
Código Erro O que fazer
401 api_key_missing, api_key_invalid a chave não existe, foi revogada ou expirou; o token OAuth expirou — atualize-o
403 scope_required a chave não tem a permissão — adicione-a em “Permissões”
400 location_required a chave tem várias unidades — informe location
404 location_not_found a unidade não existe ou a chave está limitada a outras unidades
429 rate_limited o limite foi atingido, tente novamente em Retry-After segundos

Eventos de chamadas#

Em tempo real — webhooks da central telefônica: Telefonia → API e MCP → Webhooks ou POST /v1/webhooks com uma chave com a permissão webhooks:write. No seu endereço https chega em segundos um POST a cada evento: call.started (começou: direção, quem, para onde, linha), call.ringing (em quem está tocando — um por telefone), call.answered (quem atendeu), call.transferred (quem transferiu e para quem), call.ended (resultado, duração, conversa, quem atendeu). O webhook pode ser limitado por unidades e tipos de evento.

{ "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": "Анна" } } }

Assinatura — cabeçalho X-Cenaly-Signature: t=<tempo unix>,v1=<HMAC-SHA256 de "t.corpo" com o segredo do webhook>. Recalcule, compare em tempo constante e rejeite t com mais de 5 minutos. O segredo whsec_… é mostrado uma única vez; «Novo segredo» invalida o anterior imediatamente.

Entrega — responda 2xx em 10 segundos. Caso contrário, repetimos com pausas de 10 s, 30 s, 2, 5, 10, 15 e 15 minutos (8 tentativas, cerca de uma hora); a repetição carrega o mesmo id — use-o para descartar duplicatas. O histórico de entregas (código de resposta, horário, tentativa) fica na janela do webhook e em GET /v1/webhooks/{id}/deliveries; «Verificar» envia o webhook.ping de serviço. Se o endereço não aceitou nenhuma entrega por 3 dias seguidos, o webhook se desliga sozinho: o proprietário recebe um e-mail, na janela «Webhooks» aparece a marca «Desativado automaticamente» e o botão «Ativar» (ou PATCH /v1/webhooks/{id} com { "enabled": true }).

Sem servidor próprio — o mesmo feed por consulta: GET /v1/events?since=<id do último evento> ou a ferramenta MCP get_call_events (eventos da unidade dos últimos 7 dias, até 2000; por resposta, até 500, more: true — continue a paginar com o mesmo since).

Após o processamento da gravação — a chamada com transcrição e análise chega por webhook da fonte «Webhook» na seção «Chamadas».

«Aberto / fechado» — PUT /v1/open-closed com { "closed": true } fecha a unidade até o fim do dia (como *28 pelo telefone: as chamadas seguem as regras de «fora do horário»), false — abre; GET mostra se está fechado e por quem. Com "until" — fechado até esse momento (no máximo 30 dias), depois abre sozinho: o horário sem fuso (2026-10-05T09:00) é lido no fuso da unidade; false também o remove. É preciso ter a opção «Fechar com o código *28» ativada no roteamento (caso contrário, 409).

Segurança#

  • A chave é mostrada uma única vez e guardamos apenas sua impressão digital; uma chave vazada é revogada com um botão.
  • A conexão OAuth só é autorizada pelo proprietário, e é visível para qual endereço o acesso vai; a conexão autorizada pode ser limitada por permissões e unidades e revogada a qualquer momento.
  • Números de telefone são dados pessoais dos seus clientes: conceda permissões de histórico e gravações apenas às integrações que realmente precisam delas.
  • Todas as alterações por chave ou conexão ficam no histórico de ações da central telefônica com o nome da chave ou do aplicativo.
Was this article helpful?