ExoVoIPDeveloper guide

Voice servers

Customer calls go through the main server or through one or more additional voice servers managed by the platform. This section is reserved to the platform (superadmin or global keys with the system:* and tenants:* scopes).

Adding a voice server

  1. POST /v1/voice-nodes with name (and, if available, sipHost: the server's domain name). The response contains enrollment.code (single-use activation code, valid for 24 hours) and enrollment.installCommand: they are shown only once.
  2. Run the install command on the new server (Ubuntu 22.04 or 24.04). When it finishes the server registers itself and becomes online.
curl -fsSL https://centralino.exovoip.it/api/v1/nodes/install.sh | sudo bash -s -- --token EXO-XXXX-XXXX-XXXX-XXXX --domain tel2.exovoip.it

With --domain the server obtains a certificate and enables encryption (SIP TLS) and the browser phone (WebRTC). Without a domain it works over UDP/TCP and health.warnings reports that WebRTC and TLS are not available.

Status

GET /v1/voice-nodes returns for each server state (pending, online, degraded, offline, disabled), address (sipHost, publicIp), secure connections (tlsEnabled, webrtcEnabled), versions, number of hosted companies and the last reported status (health: PBX, active calls, services, certificate, resources, warnings). A server silent for more than 3 minutes is offline.

The same summary is in GET /v1/live/health (platform.voiceNodes).

Assigning companies

PUT /v1/tenants/:id/voice-node with voiceNodeId (null = main server) and, optionally, sipHost (custom address for the company's phones). The response reports effectiveSipHost, the address the phones will use, and webrtcAvailable.

Phone credentials (GET /v1/extensions/:id/sip-credentials) follow the assignment automatically: custom address → voice server domain → voice server IP → main server address. When the browser phone is not available wssUrl is empty.

Reinstall, disable, delete

  • POST /v1/voice-nodes/:id/enrollment-code: new code to reinstall or replace the server; the current server stays connected until the code is used.
  • POST /v1/voice-nodes/:id/revoke: immediately disables the server and revokes its credentials.
  • DELETE /v1/voice-nodes/:id: only when it hosts no companies (otherwise 409 CONFLICT).

Endpoints

RequestScopeSDK method
GET /v1/voice-nodessystem:readvoiceNodes.list() · py: voice_nodes.list()
POST /v1/voice-nodessystem:writevoiceNodes.create() · py: voice_nodes.create()
GET /v1/voice-nodes/:idsystem:readvoiceNodes.get() · py: voice_nodes.get()
PATCH /v1/voice-nodes/:idsystem:writevoiceNodes.update() · py: voice_nodes.update()
DELETE /v1/voice-nodes/:idsystem:writevoiceNodes.delete() · py: voice_nodes.delete()
POST /v1/voice-nodes/:id/enrollment-codesystem:writevoiceNodes.enrollmentCode() · py: voice_nodes.enrollment_code()
POST /v1/voice-nodes/:id/revokesystem:writevoiceNodes.revoke() · py: voice_nodes.revoke()