Numéros, appels, click-to-call, webphone WebRTC, enregistrement et événements temps réel — le guide développeur pour intégrer la voix Kavkom dans votre application.
Introduction
L’API Kavkom permet d’ajouter des fonctionnalités téléphoniques à votre produit : commander des numéros et des lignes, lancer et superviser des appels, intégrer un téléphone directement dans le navigateur et recevoir les événements d’appel en temps réel.
Les briques de l’API
| Brique | Base | Rôle |
|---|---|---|
| API Billing | client.kavkom.com | Commander des extensions, aussi appelées lignes, et des numéros DID. |
| API PBX | api.kavkom.com | Lister les extensions, lancer des appels, raccrocher des appels. |
| WebSocket | live.kavkom.com | Recevoir l’état des appels entrants et sortants en temps réel. |
| Webhooks | Votre endpoint HTTPS | Recevoir les appels en direct et les CDR sur une URL de votre système. |
URLs de base & conventions
Toutes les requêtes et réponses sont en JSON. Envoyez systématiquement les en-têtes Content-Type: application/json et Accept: application/json.
| API | URL de base | Enveloppe de réponse |
|---|---|---|
| Billing | https://client.kavkom.com | { "status": "success", "return": { … } } |
| PBX | https://api.kavkom.com | { "data": { … }, "success": true, "message": "…" } |
| WebSocket | wss://live.kavkom.com | Messages JSON { "event": "…", "data": { … } } |
Authentification
Jeton API X-API-TOKEN & domain_uuid
Les API Billing et PBX utilisent un jeton API placé dans l’en-tête X-API-TOKEN, ainsi qu’un domain_uuid qui identifie le domaine client.
X-API-TOKEN: <votre-jeton-api>
- Le jeton est rattaché à un ou plusieurs domaines et à une liste de routes autorisées.
domain_uuidest un UUID v4. Il est transmis en query string pour unGETet dans le corps JSON pour unPOST.- Un jeton non autorisé pour la route demandée, ou non lié au
domain_uuid, est rejeté.
Créer une clé API
Voici comment créer une clé API :
- Connectez-vous sur l’interface applicative Kavkom avec un compte administrateur, puis accédez aux réglages avancés en cliquant sur la roue dentée en bas à gauche (1).
- Cliquez sur l’onglet Paramètres API (2), puis sur le bouton Ajouter un Token (3).
- Renseignez le nom du Token (1), activez l’autorisation d’accès au domaine et conservez le
domain_uuid(2). - Sélectionnez les objets à autoriser dans la liste à droite (3), puis sauvegardez en cliquant sur Créer (4).
- Une fois revenu sur la liste des Tokens API, copiez et conservez la clé en cliquant sur le bouton Copier dans la colonne Actions.
Jetons d’accès pour le WebSocket
La connexion WebSocket /calls utilise un access token de courte durée, obtenu via un refresh token côté serveur.
- Obtenez un refresh token avec un jeton Bearer protégé côté serveur.
- Échangez-le contre un access token avec le scope
callset les extensions autorisées.
POST https://live.kavkom.com/api/auth/acquire-access
Authorization: Bearer <refresh-token>
Content-Type: application/json
{
"userUuid": "<user-uuid>",
"extensions": [1001],
"scope": "calls",
"application": "mon-app"
}
Réponse :
{ "token": "<access-token>", "expiresAt": "<date-ISO>" }
| Endpoint | Rôle |
|---|---|
POST /api/auth/acquire-access | Obtenir un access token à partir du refresh token. |
POST /api/auth/verify-access | Vérifier et éventuellement prolonger un access token. |
POST /api/auth/revoke-access | Révoquer un access token. |
POST /api/auth/revoke-refresh | Révoquer le refresh token. |
Commander des ressources – API Billing
Les extensions et les numéros se commandent via le système de facturation, qui crée la commande, gère la facturation puis provisionne automatiquement la ressource sur le PBX. On ne crée pas d’extension directement sur le PBX.
Commander une ligne / extension
POST https://client.kavkom.com/api.php avec route=order et type=line
| Champ | Requis | Description |
|---|---|---|
route | oui | Doit valoir order. |
type | oui | Doit valoir line. |
domain_uuid | oui | UUID v4 du domaine client. |
options | oui | Carte nom d'option → quantité, par exemple { "starter": 2 }. |
curl -X POST "https://client.kavkom.com/api.php" \
-H "X-API-TOKEN: <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"route": "order",
"type": "line",
"domain_uuid": "ddcfeb62-110f-4bd7-b7a9-965e1a78295f",
"options": { "starter": 2 }
}'
Réponse de succès :
{ "invoiceid": 10231, "order_number": "0123456789" }
Commander un numéro DID
La commande est enregistrée puis, lorsque l’identité du client est validée, un numéro est attribué depuis le stock et provisionné sur le PBX avec un routage vers l’extension choisie.
POST https://client.kavkom.com/api.php avec route=order et type=did
| Champ | Requis | Description |
|---|---|---|
route | oui | Doit valoir order. |
type | oui | Doit valoir did. |
domain_uuid | oui | UUID v4 du domaine client. |
country | oui | Pays disponible dans le catalogue DID. |
location | oui | Ville ou localité disponible. |
extension | oui | Extension vers laquelle router les appels entrants. |
description | non | Libellé libre stocké avec la commande. |
identiy | non | Identifiant d’enregistrement d’identité. L’orthographe du paramètre est bien identiy. |
curl -X POST "https://client.kavkom.com/api.php" \
-H "X-API-TOKEN: <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"route": "order",
"type": "did",
"domain_uuid": "ddcfeb62-110f-4bd7-b7a9-965e1a78295f",
"country": "FR",
"location": "Paris",
"extension": "901",
"description": "Ligne commerciale"
}'
{
"status": "success",
"return": { "id": 152, "accepted": true }
}
{ "status": "error", "message": "…" }. Le provisioning instantané n’est donc pas garanti dans tous les cas.Lister les commandes de numéros
GET https://client.kavkom.com/api.php avec route=order et type=didlist
Paramètre requis : domain_uuid. Paramètres optionnels : orderby avec order_date ou accept_date, et asc.
Gérer les appels – API PBX
Lister les extensions
Retourne les extensions configurées d’un domaine, avec pagination. Une variante allégée existe : GET /api/pbx/v1/extension/list_limited.
GET https://api.kavkom.com/api/pbx/v1/extension/list
| Paramètre | Requis | Description |
|---|---|---|
domain_uuid | oui | UUID v4 du domaine. |
limit | non | Enregistrements par page, de 1 à 5000. Défaut : 15. |
page | non | Numéro de page. |
filter[search_query] | non | Texte de filtre, par exemple un numéro d’extension. |
sort[0] | non | Colonne : extension, effective_caller_id_number, outbound_caller_id_name, description. |
sort[1] | non | Sens : ASC ou DESC. |
with_user | non | 1 pour inclure l’utilisateur lié, 0 pour l’omettre. |
curl -X GET "https://api.kavkom.com/api/pbx/v1/extension/list?domain_uuid=ddcfeb62-110f-4bd7-b7a9-965e1a78295f" \
-H "X-API-TOKEN: <token>" \
-H "Accept: application/json"
{
"data": [
{
"extension_uuid": "48b0d200-2b31-4211-a3d7-b41f87abbcbb",
"domain_uuid": "ddcfeb62-110f-4bd7-b7a9-965e1a78295f",
"extension": "901",
"password": "aB3xY9zK",
"user_context": "client.kavkom.com",
"enabled": "true"
}
],
"success": true,
"message": "Action completed successfully"
}
Lancer un appel, ou click-to-call
Origine un appel : le PBX appelle d’abord l’extension source, puis la met en relation avec la destination. L’appel est enregistré automatiquement et son call_uuid est renvoyé.
POST https://api.kavkom.com/api/pbx/v1/active_call/call
| Paramètre | Requis | Description |
|---|---|---|
domain_uuid | oui | UUID v4 du domaine. |
src | oui | Extension source. Doit exister sur le domaine. |
destination | oui | Numéro à appeler : extension interne, numéro externe ou URI SIP. |
auto_answer | non | "true" pour décrocher automatiquement la source. |
ignore_early | non | Raccrocher après la mise en relation et ignorer l’early media. |
src_cid_number | non | Caller ID affiché sur la jambe source. |
curl -X POST "https://api.kavkom.com/api/pbx/v1/active_call/call" \
-H "X-API-TOKEN: <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"domain_uuid": "ddcfeb62-110f-4bd7-b7a9-965e1a78295f",
"src": "901",
"destination": "33612345678",
"auto_answer": "true"
}'
{
"success": true,
"message": "Action completed successfully",
"call_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"recording": "+OK"
}
src, sonne d’abord, puis est mise en relation avec le client.Raccrocher un appel
POST https://api.kavkom.com/api/pbx/v1/active_call/kill
Corps attendu : domain_uuid et call_uuid, le call_uuid étant renvoyé par l’origination.
Enregistrer une extension en SIP
Une fois l’extension commandée et provisionnée, tout appareil SIP ou softphone peut s’enregistrer sur le PBX. L’enregistrement, ou REGISTER, indique au switch où joindre l’utilisateur. Il est requis avant d’émettre ou de recevoir un appel.
Identifiants
| Réglage SIP | Valeur | Champ source |
|---|---|---|
| Username / Auth user | Le numéro d’extension, ex. 901 | extension |
| Password / Secret | Le secret SIP | password |
| Domain / Realm / serveur SIP | Le nom de domaine, ex. client.kavkom.com | user_context |
| Transport | UDP, TCP ou TLS. Préférez TLS. | Réglage appareil |
| Port | 5060 UDP/TCP ou 5061 TLS | Réglage appareil |
user_context de l’extension. C’est ainsi que le PBX détermine le domaine de l’appareil.Déroulé de l’enregistrement
- L’appareil envoie un
REGISTERau registrar avecusername@domain. - Le PBX répond
401 Unauthorizedavec un challenge digest. - L’appareil renvoie
REGISTERavec le digest calculé. - En cas de succès, le switch renvoie
200 OKet stocke le contact.
SIP Username : 901
Password : aB3xY9zK
SIP Domain : client.kavkom.com
Registrar : client.kavkom.com
Transport : TLS
Port : 5061
Expiry : 3600
403 Forbidden sur le REGISTER signifie généralement un mauvais mot de passe ou un realm différent de user_context. Derrière un NAT, activez un keep-alive pour rester joignable.Construire une application webphone WebRTC avec SIP.js
Cette section montre comment intégrer un téléphone directement dans le navigateur à partir des identifiants d’une extension. La référence d’implémentation utilise SIP.js et son assistant SimpleUser.
Prérequis
| Élément | Détail |
|---|---|
| Jeton API | Autorisé sur votre domaine et sur l’endpoint de liste des extensions. |
domain_uuid | UUID v4 du domaine client. |
| Extension provisionnée | Une extension doit déjà exister. |
| Navigateur moderne | Accès micro requis ; la page doit être servie en HTTPS. |
Étape 1 – Récupérer les identifiants SIP côté serveur
Appelez l’endpoint de liste des extensions pour lire les trois valeurs nécessaires à l’enregistrement : extension, password et user_context, qui correspond au domaine ou realm. Vérifiez que l’extension est enabled: "true".
Étape 2 & 3 – Enregistrer et appeler depuis le navigateur
import { Web } from "sip.js";
// 1) Récupérer les identifiants depuis VOTRE backend.
// Ne jamais appeler l'API Kavkom avec le jeton directement depuis le navigateur.
const { extension, password, user_context: domain } = await fetch(
"/api/mon-backend/sip-credentials"
).then((r) => r.json());
// 2) Construire le client SIP à partir de ces valeurs.
const sipTarget = (number) => `sip:${number}@${domain}`;
const simpleUser = new Web.SimpleUser(`wss://${domain}/`, {
aor: sipTarget(extension),
media: { remote: { audio: document.querySelector("#remoteAudio") } },
userAgentOptions: {
authorizationUsername: extension,
authorizationPassword: password,
},
delegate: {
onServerConnect: () => simpleUser.register(),
onCallReceived: () => simpleUser.answer(),
},
});
// 3) Connexion + enregistrement, puis appels.
await simpleUser.connect(); // déclenche onServerConnect -> register()
// await simpleUser.call(sipTarget("33612345678"));
// await simpleUser.hangup();
Pendant un appel, le client peut gérer la mise en attente, le micro, le transfert et le clavier DTMF.
Variante – Originer depuis le serveur
Plutôt que de laisser le client composer, vous pouvez démarrer l’appel depuis votre backend avec l’endpoint d’origination. C’est utile pour un bouton click-to-call où l’extension de l’utilisateur doit sonner en premier.
La connexion échoue immédiatement
Le domaine est faux : il doit être égal à user_context et joignable en wss://<domain>/. La page doit être en HTTPS.
L’extension s’enregistre puis se déconnecte
Vérifiez le mot de passe et assurez-vous que le realm correspond à user_context.
Il n’y a pas de son
La permission micro a probablement été refusée, ou aucun élément <audio> n’est lié au média distant.
Impossible d’appeler
Vérifiez que l’extension est enabled: "true" et que le format de destination est correct.
Événements d’appel en temps réel – WebSocket
Le WebSocket /calls pousse l’état des appels en temps réel pour les extensions demandées.
Connexion
WSS wss://live.kavkom.com/calls?t=<access-token>&ext=1001
| Paramètre | Description |
|---|---|
t | Access token obtenu via acquire-access avec le scope calls. |
ext | Liste d’extensions séparées par des virgules, par exemple 1001 ou 1001,1002. |
tmanquant : le serveur répond406, «&t parameter is missing».extmanquant :406, «&ext parameter is missing».- Token invalide ou expiré : connexion rejetée avec
401ouInvalid token.
Messages reçus
| Événement | Description |
|---|---|
call | Mise à jour de l’état d’un appel : ringing, active, held, finished. |
ping | Battement de cœur ; le client doit répondre par pong. |
error | Message d’erreur dans data.message. |
Charge utile d’un événement call
{
"event": "call",
"data": {
"callUuid": "abc-123",
"state": "active",
"direction": "inbound",
"number": "380501234567",
"presenceId": "1001@contact.example.kavkom.com",
"createdEpoch": 1710763200,
"answeredEpoch": 1710763205,
"duration": 120
}
}
Ping / Pong
Le serveur envoie ping avec data: { sentStamp, expiresInSec }. Le client doit renvoyer un pong de même structure.
{ "event": "pong", "data": { "sentStamp": 1710763200000, "expiresInSec": 60 } }
Exemple client JavaScript
const ws = new WebSocket(
`wss://live.kavkom.com/calls?t=${token}&ext=1001`
);
ws.onmessage = (msg) => {
const { event, data } = JSON.parse(msg.data);
if (event === "call") console.log(data.state, data.direction, data.number);
if (event === "ping") ws.send(JSON.stringify({ event: "pong", data }));
};
Webhooks – push des appels & CDR
Depuis l’interface Kavkom, dans Advanced → Integrations → Webhook, configurez une URL vers laquelle Kavkom enverra les événements d’appel. Ce mécanisme est utile pour le screen-pop, le log dans un CRM, le déclenchement de workflows ou les tableaux de bord temps réel.
Paramètres de configuration
| Champ | Description |
|---|---|
| Endpoint | URL HTTPS de votre serveur. Un bouton de test permet de la valider. |
| Headers | En-têtes personnalisés, par exemple Authorization: Bearer …. |
| Variables | Variables personnalisées ajoutées au payload. |
| Types d’appels | Appels entrants en direct, appels sortants en direct, et/ou CDR après la fin de l’appel. |
| Mapping | Correspondance des champs Kavkom vers ceux attendus par votre système. |
Exemple de payload reçu
POST /webhooks/calls HTTP/1.1
Authorization: Bearer <votre-cle>
Content-Type: application/json
{
"event": "cdr",
"callUuid": "a1b2c3d4-...-ef1234567890",
"direction": "outbound",
"number": "33612345678",
"state": "finished",
"duration": 120
}
Référence des endpoints
| Méthode & chemin | API | Rôle |
|---|---|---|
POST /api.php (route=order, type=line) | Billing | Commander une ligne / extension. |
POST /api.php (route=order, type=did) | Billing | Commander un numéro DID. |
GET /api.php (route=order, type=didlist) | Billing | Lister les commandes DID. |
GET /api/pbx/v1/extension/list | PBX | Lister les extensions. |
GET /api/pbx/v1/extension/list_limited | PBX | Liste allégée des extensions. |
POST /api/pbx/v1/active_call/call | PBX | Lancer un appel. |
POST /api/pbx/v1/active_call/kill | PBX | Raccrocher un appel. |
POST /api/auth/acquire-access | Auth | Obtenir un access token WebSocket. |
POST /api/auth/verify-access | Auth | Vérifier ou prolonger le token. |
POST /api/auth/revoke-access | Auth | Révoquer l’access token. |
WSS /calls?t=&ext= | WebSocket | Flux d’événements d’appel. |
Codes d’erreur & dépannage
Forme des erreurs
API Billing :
{ "status": "error", "message": "Fields required: domain_uuid, options" }
API PBX :
{
"error": true,
"message": "Model is not valid",
"validationErrors": { "extension": "The extension field is required." }
}
| Cas | Signification / action |
|---|---|
422 + « src invalid » | L’extension source n’existe pas sur ce domaine. |
422 + texte switch -ERR … | L’appel a été refusé par le switch. |
| Jeton refusé | Le jeton n’est pas autorisé pour la route, ou non lié au domain_uuid fourni. |
406 WebSocket | Paramètre t ou ext manquant. |
401 WebSocket | Token invalide ou expiré. |
403 SIP REGISTER | Mauvais mot de passe ou realm différent de user_context. |
Glossaire
| Terme | Définition |
|---|---|
| DID | Direct Inward Dialing : numéro de téléphone joignable directement. |
| Extension / ligne | Poste téléphonique sur le PBX, identifié par un numéro court, par exemple 901. |
domain_uuid | UUID v4 identifiant le client, ou tenant, sur la plateforme. |
| CDR | Call Detail Record : métadonnées d’un appel terminé. |
| IVR | Serveur vocal interactif, ou menu à touches. |
| SIP | Protocole d’ouverture de session pour la voix sur IP. |
| WebRTC | Technologie de communication temps réel dans le navigateur. |
| Bridge | Mise en relation de deux jambes d’appel. |