Intégration & API

Integration & API

Kavkom API Documentation

Phone numbers, calls, click-to-call, WebRTC webphones, recording, and real-time events — the developer guide to integrating Kavkom Voice into your application.

Introduction

The Kavkom API lets you add telephony features to your product: order phone numbers and lines, start and monitor calls, embed a phone directly in the browser, and receive real-time call events.

API building blocks

ComponentBaseRole
Billing APIclient.kavkom.comOrder extensions, also called lines, and DID numbers.
PBX APIapi.kavkom.comList extensions, start calls, hang up calls.
WebSocketlive.kavkom.comReceive the status of inbound and outbound calls in real time.
WebhooksYour HTTPS endpointReceive live calls and CDRs on a URL from your system.

Base URLs & conventions

All requests and responses use JSON. Always send the Content-Type: application/json and Accept: application/json headers.

APIBase URLResponse envelope
Billinghttps://client.kavkom.com{ "status": "success", "return": { … } }
PBXhttps://api.kavkom.com{ "data": { … }, "success": true, "message": "…" }
WebSocketwss://live.kavkom.comJSON messages { "event": "…", "data": { … } }

Authentication

API token X-API-TOKEN & domain_uuid

The Billing and PBX APIs use an API token placed in the X-API-TOKEN header, together with a domain_uuid that identifies the customer domain.

X-API-TOKEN: <your-api-token>
  • The token is linked to one or more domains and to a list of authorized routes.
  • domain_uuid is a UUID v4. It is sent in the query string for a GET request and in the JSON body for a POST request.
  • A token that is not authorized for the requested route, or not linked to the supplied domain_uuid, is rejected.

Create an API key

Here is how to create an API key:

  1. Log in to the Kavkom application interface with an administrator account, then open the advanced settings by clicking the gear icon at the bottom left (1).
  2. Click the API Settings tab (2), then click the Add Token button (3).
  3. Enter the Token name (1), enable domain access authorization and keep the domain_uuid (2).
  4. Select the objects to authorize from the list on the right (3), then save by clicking Create (4).
  5. Once you are back on the API Tokens list, copy and store the key by clicking the Copy button in the Actions column.

Access tokens for the WebSocket

The /calls WebSocket connection uses a short-lived access token obtained from a refresh token on the server side.

  1. Obtain a refresh token with a protected Bearer token on the server side.
  2. Exchange it for an access token with the calls scope and the authorized extensions.
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": "my-app"
}

Response:

{ "token": "<access-token>", "expiresAt": "<ISO-date>" }
EndpointRole
POST /api/auth/acquire-accessObtain an access token from the refresh token.
POST /api/auth/verify-accessVerify and optionally extend an access token.
POST /api/auth/revoke-accessRevoke an access token.
POST /api/auth/revoke-refreshRevoke the refresh token.
Security. Never expose the API token in the browser. The token must remain on your backend. The front end asks your server for the required data, and your server calls the Kavkom API.

Ordering resources – Billing API

Extensions and numbers are ordered through the billing system, which creates the order, handles billing and then automatically provisions the resource on the PBX. Extensions are not created directly on the PBX.

Order a line / extension

POST https://client.kavkom.com/api.php with route=order and type=line

FieldRequiredDescription
routeyesMust be order.
typeyesMust be line.
domain_uuidyesUUID v4 of the customer domain.
optionsyesMap of option name → quantity, for example { "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 }
  }'

Successful response:

{ "invoiceid": 10231, "order_number": "0123456789" }

Order a DID number

The order is registered and, once the customer’s identity has been validated, a number is allocated from the stock and provisioned on the PBX with routing to the selected extension.

POST https://client.kavkom.com/api.php with route=order and type=did

FieldRequiredDescription
routeyesMust be order.
typeyesMust be did.
domain_uuidyesUUID v4 of the customer domain.
countryyesCountry available in the DID catalog.
locationyesAvailable city or locality.
extensionyesExtension to route inbound calls to.
descriptionnoFree label stored with the order.
identiynoIdentity registration identifier. The parameter spelling is intentionally 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": "Sales line"
  }'
{
  "status": "success",
  "return": { "id": 152, "accepted": true }
}
KYC identity. If the country or locality is not available, or if the identity has not been validated, the response is { "status": "error", "message": "…" }. Instant provisioning is therefore not guaranteed in all cases.

List number orders

GET https://client.kavkom.com/api.php with route=order and type=didlist

Required parameter: domain_uuid. Optional parameters: orderby with order_date or accept_date, and asc.

Managing calls – PBX API

List extensions

Returns the extensions configured for a domain, with pagination. A lightweight variant is also available: GET /api/pbx/v1/extension/list_limited.

GET https://api.kavkom.com/api/pbx/v1/extension/list

ParameterRequiredDescription
domain_uuidyesUUID v4 of the domain.
limitnoRecords per page, from 1 to 5000. Default: 15.
pagenoPage number.
filter[search_query]noFilter text, for example an extension number.
sort[0]noColumn: extension, effective_caller_id_number, outbound_caller_id_name, description.
sort[1]noDirection: ASC or DESC.
with_userno1 to include the linked user, 0 to omit it.
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"
}

Start a call, or click-to-call

Originates a call: the PBX first calls the source extension, then bridges it to the destination. The call is automatically recorded and its call_uuid is returned.

POST https://api.kavkom.com/api/pbx/v1/active_call/call

ParameterRequiredDescription
domain_uuidyesUUID v4 of the domain.
srcyesSource extension. Must exist on the domain.
destinationyesNumber to call: internal extension, external number or SIP URI.
auto_answerno"true" to automatically answer the source leg.
ignore_earlynoHang up after bridging and ignore early media.
src_cid_numbernoCaller ID displayed on the source leg.
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"
}
Ideal for a Call button: the agent’s extension, src, rings first and is then connected to the customer.

Hang up a call

POST https://api.kavkom.com/api/pbx/v1/active_call/kill

Expected body: domain_uuid and call_uuid, where call_uuid is returned by the origination endpoint.

Register an extension with SIP

Once the extension has been ordered and provisioned, any SIP device or softphone can register on the PBX. The registration, or REGISTER, tells the switch where the user can be reached. It is required before making or receiving calls.

Credentials

SIP settingValueSource field
Username / Auth userThe extension number, e.g. 901extension
Password / SecretThe SIP secretpassword
Domain / Realm / SIP serverThe domain name, e.g. client.kavkom.comuser_context
TransportUDP, TCP or TLS. Prefer TLS.Device setting
Port5060 UDP/TCP or 5061 TLSDevice setting
The SIP realm must match the extension’s user_context. This is how the PBX determines the device domain.

Registration flow

  1. The device sends a REGISTER request to the registrar with username@domain.
  2. The PBX replies with 401 Unauthorized and a digest challenge.
  3. The device sends another REGISTER with the computed digest.
  4. On success, the switch returns 200 OK and stores the contact.
SIP Username : 901
Password     : aB3xY9zK
SIP Domain   : client.kavkom.com
Registrar    : client.kavkom.com
Transport    : TLS
Port         : 5061
Expiry       : 3600
Troubleshooting. A 403 Forbidden on REGISTER generally means an incorrect password or a realm that differs from user_context. Behind NAT, enable keep-alive to remain reachable.

Build a WebRTC webphone application with SIP.js

This section shows how to embed a phone directly in the browser using an extension’s credentials. The reference implementation uses SIP.js and its SimpleUser helper.

Prerequisites

ItemDetails
API tokenAuthorized for your domain and for the extension list endpoint.
domain_uuidUUID v4 of the customer domain.
Provisioned extensionAn extension must already exist.
Modern browserMicrophone access is required; the page must be served over HTTPS.

Step 1 – Retrieve SIP credentials on the server side

Call the extension list endpoint to read the three values required for registration: extension, password and user_context, which corresponds to the domain or realm. Check that the extension is enabled: "true".

Steps 2 & 3 – Register and call from the browser

import { Web } from "sip.js";

// 1) Retrieve credentials from YOUR backend.
// Never call the Kavkom API with the token directly from the browser.
const { extension, password, user_context: domain } = await fetch(
  "/api/my-backend/sip-credentials"
).then((r) => r.json());

// 2) Build the SIP client from those values.
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) Connect + register, then place calls.
await simpleUser.connect(); // triggers onServerConnect -> register()
// await simpleUser.call(sipTarget("33612345678"));
// await simpleUser.hangup();

During a call, the client can handle hold, mute, transfer and the DTMF keypad.

Variant – Originate from the server

Instead of letting the client dial, you can start the call from your backend with the origination endpoint. This is useful for a click-to-call button where the user’s extension should ring first.

The connection fails immediately

The domain is wrong: it must match user_context and be reachable at wss://<domain>/. The page must be served over HTTPS.

The extension registers, then disconnects

Check the password and make sure the realm matches user_context.

There is no audio

Microphone permission was probably denied, or no <audio> element is linked to the remote media.

Calls cannot be placed

Check that the extension is enabled: "true" and that the destination format is correct.

Real-time call events – WebSocket

The /calls WebSocket pushes call status in real time for the requested extensions.

Connection

WSS wss://live.kavkom.com/calls?t=<access-token>&ext=1001

ParameterDescription
tAccess token obtained via acquire-access with the calls scope.
extComma-separated list of extensions, for example 1001 or 1001,1002.
  • Missing t: the server returns 406, “&t parameter is missing”.
  • Missing ext: 406, “&ext parameter is missing”.
  • Invalid or expired token: connection rejected with 401 or Invalid token.

Received messages

EventDescription
callCall state update: ringing, active, held, finished.
pingHeartbeat; the client must reply with pong.
errorError message in data.message.

call event payload

{
  "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

The server sends ping with data: { sentStamp, expiresInSec }. The client must return a pong with the same structure.

{ "event": "pong", "data": { "sentStamp": 1710763200000, "expiresInSec": 60 } }

JavaScript client example

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 – pushing calls & CDRs

From the Kavkom interface, under Advanced → Integrations → Webhook, configure a URL to which Kavkom will send call events. This mechanism is useful for screen-pop, CRM logging, workflow triggering or real-time dashboards.

Configuration parameters

FieldDescription
EndpointHTTPS URL of your server. A test button lets you validate it.
HeadersCustom headers, for example Authorization: Bearer ….
VariablesCustom variables added to the payload.
Call typesLive inbound calls, live outbound calls, and/or CDRs after the call ends.
MappingMapping between Kavkom fields and the fields expected by your system.

Example received payload

POST /webhooks/calls HTTP/1.1
Authorization: Bearer <your-key>
Content-Type: application/json

{
  "event": "cdr",
  "callUuid": "a1b2c3d4-...-ef1234567890",
  "direction": "outbound",
  "number": "33612345678",
  "state": "finished",
  "duration": 120
}
Native connectors. Without writing code, you can also connect HubSpot, Salesforce, Pipedrive, Zoho or Fireberry directly from the same integrations screen.
Good to know. Kavkom webhooks push events to your endpoint. Your server’s HTTP response does not control the call flow: call control is handled via the REST endpoints and the SIP client.

Endpoint reference

Method & pathAPIRole
POST /api.php (route=order, type=line)BillingOrder a line / extension.
POST /api.php (route=order, type=did)BillingOrder a DID number.
GET /api.php (route=order, type=didlist)BillingList DID orders.
GET /api/pbx/v1/extension/listPBXList extensions.
GET /api/pbx/v1/extension/list_limitedPBXLightweight extension list.
POST /api/pbx/v1/active_call/callPBXStart a call.
POST /api/pbx/v1/active_call/killPBXHang up a call.
POST /api/auth/acquire-accessAuthGet a WebSocket access token.
POST /api/auth/verify-accessAuthVerify or extend the token.
POST /api/auth/revoke-accessAuthRevoke the access token.
WSS /calls?t=&ext=WebSocketCall event stream.

Error codes & troubleshooting

Error format

Billing API:

{ "status": "error", "message": "Fields required: domain_uuid, options" }

PBX API:

{
  "error": true,
  "message": "Model is not valid",
  "validationErrors": { "extension": "The extension field is required." }
}
CaseMeaning / action
422 + “src invalid”The source extension does not exist on this domain.
422 + switch text -ERR …The call was rejected by the switch.
Rejected tokenThe token is not authorized for the route, or is not linked to the supplied domain_uuid.
406 WebSocketMissing t or ext parameter.
401 WebSocketInvalid or expired token.
403 SIP REGISTERIncorrect password or realm different from user_context.

Glossary

TermDefinition
DIDDirect Inward Dialing: a phone number that can be reached directly.
Extension / lineTelephone endpoint on the PBX, identified by a short number such as 901.
domain_uuidUUID v4 identifying the customer, or tenant, on the platform.
CDRCall Detail Record: metadata for a completed call.
IVRInteractive voice response, or touch-tone menu.
SIPSession initiation protocol for voice over IP.
WebRTCReal-time communication technology in the browser.
BridgeConnection of two call legs.
Contents