C cenaly.com
Commencer gratuitement

API et MCP de votre propre standard téléphonique

Clés et autorisations, API REST, serveur MCP pour Claude et Cursor, connexion de ChatGPT et claude.ai via OAuth sans clé, exemples, limites et erreurs

On this page 10

API et MCP de votre propre PBX

Votre PBX Cenaly est ouverte à vos programmes et à vos assistants IA :

  • CRM, système de gestion, votre site — REST API : journal des appels, enregistrements et transcriptions, appel en un clic, postes, renvoi, règles d'appel ;
  • Claude Code, Claude Desktop, Cursor — serveur MCP distant par clé ;
  • ChatGPT, claude.ai, Perplexity, Cursor et VS Code — le même serveur MCP sans clé : vous vous connectez à votre compte et autorisez l'accès (OAuth).

Tout fonctionne au nom du propriétaire du compte et uniquement avec les droits qu'il a accordés. Chaque modification est visible dans le journal des actions de la PBX avec le nom de la clé ou de l'application.

Adresses#

Quoi Adresse
REST API https://api.cenaly.com/pbx-api/v1
Serveur MCP (streamable HTTP) https://api.cenaly.com/pbx-api/mcp
Documentation des méthodes api.cenaly.com/pbx-api/v1/docs
Description OpenAPI 3.1 api.cenaly.com/pbx-api/v1/openapi.json
Métadonnées OAuth https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api

Clé et droits#

La clé est créée uniquement par le propriétaire du compte : Téléphonie → API et MCP → Clés → Créer une clé. Un employé avec le rôle « Administrateur PBX » ne voit pas les clés — la clé agit au nom du propriétaire.

  • La clé de type cpx_… n'est affichée qu'une seule fois — immédiatement après sa création, avec les extraits prêts à l'emploi pour la connexion. Nous ne conservons que son empreinte (SHA-256), il est impossible de restaurer la clé — seulement d'en émettre une nouvelle.
  • La clé peut être limitée par établissements (sinon — tous les établissements, y compris les futurs) et par durée (30, 90, 365 jours ou illimitée).
  • « Droits » modifie les droits et les établissements de la clé à la volée : l'intégration continue de fonctionner, les nouveaux droits s'appliquent dès la requête suivante.
  • « Révoquer » — immédiat et définitif : la requête suivante avec cette clé recevra 401.
  • Clés et connexions actives — jusqu'à 20 par compte.

Les droits sont choisis par ensemble prêt à l'emploi ou par cases à cocher :

Droit Ce qu'il donne Ensembles
calls:read journal des appels et fiche d'appel avec le parcours CRM, assistant IA, lecture seule, tout
recordings:read lien vers l'enregistrement de la conversation (10 minutes) et transcription CRM, assistant IA, lecture seule, tout
calls:dial appel en un clic : le téléphone de l'employé sonne d'abord, après la réponse la PBX compose le numéro CRM, assistant IA, tout
extensions:read postes, groupes, renvoi, « ne pas déranger » CRM, assistant IA, lecture seule, tout
extensions:write modifier le renvoi personnel et « ne pas déranger » assistant IA, tout
presence:read qui est libre, en appel, en conversation assistant IA, lecture seule, tout
reports:read métriques du centre d'appels sur une période : niveau de service, attente, appels abandonnés, AHT, FCR, CSAT, où nous perdons des appels, répartitions par files, lignes, employés lecture seule, tout
routes:read numéros, règles d'appels entrants et sortants, historique des règles lecture seule, tout
routes:write créer, modifier, supprimer et réordonner les règles d'appel, restaurer depuis l'historique uniquement par case à cocher dédiée
config:export export des paramètres de la PBX au format fichier uniquement par case à cocher dédiée
config:import import des paramètres depuis des tableaux : aperçu, puis application uniquement par case à cocher dédiée
webhooks:write créer, modifier, tester et supprimer les webhooks d'événements d'appels uniquement par case à cocher dédiée
daynight:write fermer un établissement jusqu'à la fin de la journée ou jusqu'à une date, ouvrir — équivalent à *28 depuis le téléphone uniquement par case à cocher dédiée

Les droits qui modifient quelque chose ou consomment des minutes sont marqués en ambre dans la fenêtre. Les trois derniers droits ne font partie d'aucun ensemble, même de « Tout » — ils ne peuvent être accordés que consciemment, par une case à cocher dédiée.

ChatGPT, claude.ai, Perplexity, Cursor, VS Code : connexion sans clé#

Les assistants cloud ne savent pas insérer une clé dans l'en-tête — ils connectent le serveur MCP via OAuth. Aucune clé à créer.

claude.ai : Paramètres → Connecteurs → Ajouter votre connecteur → collez https://api.cenaly.com/pbx-api/mcp → Connecter.

ChatGPT : Paramètres → Applications et connecteurs → Avancé → activez le mode développeur → Créer → collez https://api.cenaly.com/pbx-api/mcp, authentification — OAuth.

Perplexity : Paramètres du compte → Connecteurs → « + Votre connecteur » → Distant → collez https://api.cenaly.com/pbx-api/mcp, authentification — OAuth.

Cursor et VS Code : ajoutez un serveur MCP distant (HTTP) avec l'adresse https://api.cenaly.com/pbx-api/mcp sans en-tête avec clé — la fenêtre de connexion s'ouvrira dans le navigateur. Dans Cursor : .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}} ; dans VS Code : commande « MCP: Add Server » → HTTP.

Ensuite, l'assistant ouvrira la fenêtre de connexion Cenaly. Après la connexion, vous verrez :

  • qui demande l'accès — l'application est nommée d'après l'adresse vers laquelle la réponse reviendra : « Connecteur vérifié · chatgpt.com » (idem — claude.ai, perplexity.ai, vscode.dev, Cursor), « Programme sur cet ordinateur » ou l'avertissement « Adresse inconnue ». Le nom envoyé par l'application est affiché en petit — n'importe qui peut l'écrire ;
  • les droits — ce que l'application demande est coché (si elle demande « tout », l'ensemble « assistant IA » est coché) ; les droits « uniquement par case à cocher dédiée » ne sont jamais cochés d'avance ;
  • les établissements — tous ou sélectionnés.

« Autoriser » vous ramène dans l'assistant, qui voit immédiatement les outils de la PBX. La connexion apparaît dans Téléphonie → API et MCP → Clés sous forme de ligne avec le libellé OAuth et l'adresse de l'application — c'est là que les droits se modifient et que l'accès se révoque. Reconnecter la même application met à jour ses droits, sans créer une seconde connexion.

Seul le propriétaire du compte peut autoriser les connexions.

Claude Code, Claude Desktop, Cursor : connexion par clé#

Claude Code — en une seule commande :

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

Claude Desktop, Cursor (.cursor/mcp.json) et autres clients avec un fichier de configuration :

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

Les extraits prêts à coller avec votre clé s'affichent immédiatement après la création de la clé. L'assistant ne voit que les outils autorisés par la clé et peut répondre à « qui a appelé aujourd'hui sans réussir à joindre », « rappelle ce client depuis le téléphone d'Anna », « active le renvoi vers mon mobile ».

REST API#

La clé se place dans l'en-tête Authorization: Bearer <clé> (ou X-Api-Key). Si la clé ne couvre qu'un seul établissement, le paramètre location peut être omis ; si elle en couvre plusieurs, la réponse 400 location_required les énumère.

Méthode Chemin Droit Ce qu'il fait
GET /v1/me — droits, établissements et limites de la clé
GET /v1/locations — établissements de la clé et leurs PBX
GET /v1/calls calls:read journal des appels : since, until, direction, status (answered, missed, ai), number, extension, limit jusqu'à 100, cursor
GET /v1/calls/{id} calls:read appel avec son parcours : quelle règle s'est déclenchée, quel téléphone a sonné, qui a répondu
GET /v1/calls/{id}/recording recordings:read lien vers l'enregistrement pendant 10 minutes
GET /v1/calls/{id}/transcript recordings:read transcription et résumé de la conversation
POST /v1/dial calls:dial appel en un clic : { "extension": "101", "number": "+995555123456" }
GET /v1/dial/{commandId} calls:dial état d'avancement de l'appel en un clic
GET /v1/extensions extensions:read postes supplémentaires, groupes, renvoi, « ne pas déranger »
PUT /v1/extensions/{ext}/forwarding extensions:write renvoi personnel d'un poste supplémentaire
PUT /v1/extensions/{ext}/dnd extensions:write « ne pas déranger » : { "on": true }
GET /v1/presence presence:read qui est disponible en ce moment
GET /v1/metrics reports:read métriques du centre d'appels sur une période : from, to (dates locales de l'établissement YYYY-MM-DD, par défaut les 7 derniers jours), compare (prev, year, prev,year ou vide), sections (metrics,loss,queues,lines,operators,directions,heatmap,daily), callbacks=true — en plus la rapidité de rappel
GET /v1/routes routes:read numéros, règles d'appels entrants et sortants
GET /v1/routes/history routes:read historique des modifications des règles
POST, PUT, DELETE /v1/routes/inbound…, /v1/routes/outbound… routes:write règles d'appels une par une : créer, modifier les champs transmis, supprimer, réordonner, rétablir
GET, POST /v1/config/export, /v1/config/import config:export, config:import paramètres au format fichier ; l'import — aperçu, puis application
GET /v1/events calls:read événements d'appels de l'établissement sur 7 jours (jusqu'à 2000) : since (id d'événement ou horodatage), types, limit (jusqu'à 500 par réponse)
GET, POST, PATCH, DELETE /v1/webhooks… webhooks:write webhooks : liste, créer, modifier, supprimer ; …/rotate-secret, …/test, …/deliveries
GET, PUT /v1/open-closed routes:read, daynight:write si c'est fermé et jusqu'à quand ; fermer jusqu'à la fin de la journée { "closed": true }, jusqu'à une date { "closed": true, "until": "2026-10-05T09:00" } ou ouvrir

La description complète des champs se trouve sur la page de documentation et dans l'OpenAPI.

Qui a appelé aujourd'hui sans réussir à joindre :

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

Rappeler un client depuis le téléphone du poste supplémentaire 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étriques de septembre avec comparaison à août et à septembre de l'année dernière — pour votre propre tableau de bord 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"

Dans la réponse, metrics contient les mêmes chiffres que sur l'écran Téléphonie → Journal des appels → Analytique : appels entrants, pris et manqués, niveau de service (seuil et objectif — issus des paramètres de la file d'attente), attente moyenne et maximale, part des abandons sans attente courte, AHT, FCR, part des transferts et du bot, CSAT. compare.prev et compare.year — les mêmes champs sur la période précédente et sur la même période un an plus tôt. La comparaison avec l'année dernière est calculée pour des périodes allant jusqu'à 400 jours.

Activer le renvoi vers un mobile si l'employé n'a pas répondu dans les 15 secondes :

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"

Outils MCP#

Les mêmes opérations que REST. Le client ne voit que les outils autorisés par la clé ou la connexion :

Outils Droit
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

Le serveur fonctionne sans sessions (streamable HTTP, JSON-RPC 2.0) : initialize, tools/list, tools/call.

OAuth pour les développeurs de leurs propres connecteurs#

Le serveur d'autorisation suit la spécification d'autorisation MCP — tout client qui la prend en charge convient :

  1. Une requête vers MCP sans jeton reçoit 401 avec l'en-tête WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp".
  2. Les métadonnées de la ressource (RFC 9728) désignent le serveur d'autorisation — https://api.cenaly.com/pbx-api ; ses métadonnées (RFC 8414) se trouvent à l'adresse https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api (et …/pbx-api/.well-known/openid-configuration).
  3. Enregistrement dynamique du client (RFC 7591) : POST /pbx-api/oauth/register. L'adresse de retour — uniquement localhost / 127.0.0.1 (n'importe quel port) ou l'adresse d'un connecteur connu (claude.ai, claude.com, chatgpt.com, chat.openai.com, vscode.dev, www.perplexity.ai, enterprise.perplexity.ai ; pour Cursor — en plus exactement cursor://anysphere.cursor-mcp/oauth/callback). La méthode d'authentification du client — none (client public), client_secret_post ou client_secret_basic.
  4. Code d'autorisation avec PKCE (uniquement S256) : GET /pbx-api/oauth/authorize → fenêtre de connexion et de consentement du propriétaire → retour vers votre adresse avec code, state et iss. Le paramètre resource — l'adresse du serveur MCP.
  5. Jetons : POST /pbx-api/oauth/token. Le code est à usage unique et vit 2 minutes (un code_verifier incorrect l'annule) ; le jeton d'accès — 1 heure ; le jeton de rafraîchissement — 90 jours, à chaque rafraîchissement un nouveau est délivré, le précédent cesse de fonctionner.
  6. Révocation : POST /pbx-api/oauth/revoke (RFC 7009) annule la connexion entièrement — comme « Révoquer » dans la fenêtre « API et MCP ».

Le jeton d'accès est accepté partout où la clé l'est : dans MCP comme dans REST, avec les droits et les établissements que le propriétaire a autorisés.

Limites et erreurs#

  • Par clé ou connexion : 120 requêtes par minute et 20 000 par jour (REST et MCP ensemble).
  • Appel en un clic — séparément : 10 par minute et 300 par jour.
  • Journal — jusqu'à 100 appels par requête ; dans le journal du PBX, les établissements — les 400 derniers appels sur 90 jours.
Code Erreur Que faire
401 api_key_missing, api_key_invalid la clé est absente, révoquée ou expirée ; le jeton OAuth a expiré — rafraîchissez-le
403 scope_required la clé n'a pas le droit — ajoutez-le dans « Droits »
400 location_required la clé couvre plusieurs établissements — transmettez location
404 location_not_found l'établissement n'existe pas ou la clé est limitée à d'autres établissements
429 rate_limited limite atteinte, réessayez après Retry-After secondes

Événements d'appels#

En temps réel — webhooks du PBX : Téléphonie → API et MCP → Webhooks ou POST /v1/webhooks avec une clé disposant du droit webhooks:write. Un POST arrive en quelques secondes à votre adresse https pour chaque événement : call.started (a commencé : sens, qui, vers où, ligne), call.ringing (chez qui ça sonne — un par téléphone), call.answered (qui a répondu), call.transferred (qui a transféré et à qui), call.ended (résultat, durée, conversation, qui a répondu). Le webhook peut être limité par établissements et par types d'événements.

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

Signature — en-tête X-Cenaly-Signature: t=<temps unix>,v1=<HMAC-SHA256 de "t.corps" avec le secret du webhook>. Recalculez, comparez en temps constant et rejetez un t de plus de 5 minutes. Le secret whsec_… n'est affiché qu'une fois ; « Nouveau secret » invalide immédiatement le précédent.

Livraison — répondez 2xx en 10 secondes. Sinon, nous réessayons avec des pauses de 10 s, 30 s, 2, 5, 10, 15 et 15 minutes (8 tentatives, environ une heure) ; la nouvelle tentative porte le même id — utilisez-le pour écarter les doublons. Le journal des livraisons (code de réponse, heure, tentative) se trouve dans la fenêtre du webhook et via GET /v1/webhooks/{id}/deliveries ; « Vérifier » envoie un webhook.ping de service. Si l'adresse n'a accepté aucune livraison pendant 3 jours consécutifs, le webhook se désactive tout seul : le propriétaire reçoit un e-mail, la fenêtre « Webhooks » affiche la mention « Désactivé automatiquement » et le bouton « Activer » (ou PATCH /v1/webhooks/{id} avec { "enabled": true }).

Sans votre propre serveur — le même flux par interrogation : GET /v1/events?since=<id du dernier événement> ou l'outil MCP get_call_events (événements de l'établissement sur les 7 derniers jours, jusqu'à 2000 ; par réponse, jusqu'à 500, more: true — continuez avec le même since).

Après le traitement de l'enregistrement — un appel avec transcription et analyse arrive par webhook de la source « Webhook » dans la section « Appels ».

« Ouvert / fermé » — PUT /v1/open-closed avec { "closed": true } ferme l'établissement jusqu'à la fin de la journée (comme *28 depuis le téléphone : les appels suivent les règles « hors horaires »), false — l'ouvre ; GET indique s'il est fermé et par qui. Avec "until" — fermé jusqu'à ce moment (pas au-delà de 30 jours), puis réouverture automatique : une heure sans décalage (2026-10-05T09:00) est lue dans le fuseau de l'établissement ; false l'annule aussi. La case « Fermer par le code *28 » doit être activée dans le routage (sinon 409).

Sécurité#

  • La clé n'est affichée qu'une fois et n'est conservée chez nous que sous forme d'empreinte ; une clé compromise se révoque d'un simple bouton.
  • Seul le propriétaire autorise une connexion OAuth, et l'on voit à quelle adresse l'accès est transmis ; une connexion autorisée peut être limitée par droits et par établissements et révoquée à tout moment.
  • Les numéros de téléphone sont des données personnelles de vos clients : n'accordez les droits sur le journal et les enregistrements qu'aux intégrations qui en ont réellement besoin.
  • Toutes les modifications via une clé ou une connexion figurent dans le journal d'actions du PBX avec le nom de la clé ou de l'application.
Was this article helpful?