Real-time
Real-time phone system status: active calls, extensions and connected phones, trunks, queues, call parking and service status. Available through REST requests (status snapshot) and SSE or WebSocket events (updates). Scope live:read.
Status snapshot
curl -s https://centralino.exovoip.it/api/v1/live/snapshot -H "X-API-Key: $EXOPBX_API_KEY"
curl -s https://centralino.exovoip.it/api/v1/live/extensions -H "X-API-Key: $EXOPBX_API_KEY"const snap = await pbx.live.snapshot();
console.log(`${snap.channels.length} chiamate in corso`);
const { extensions } = await pbx.live.extensions();
const offline = extensions.filter((e) => e.availability === 'offline');$snap = $pbx->live->snapshot();
$extensions = $pbx->live->extensions()['extensions'];snap = pbx.live.snapshot()
extensions = pbx.live.extensions()["extensions"]
offline = [e for e in extensions if e["availability"] == "offline"]| Endpoint | Content |
|---|---|
GET /v1/live/snapshot | Everything in one call: calls, extensions, trunks, queues, parking, health |
GET /v1/live/channels | Active calls |
GET /v1/live/extensions | Extensions: status, registration, availability, Do Not Disturb, devices |
GET /v1/live/devices | One item per registered phone (IP, user agent, latency, reachability) |
GET /v1/live/trunks | Trunks: registration, reachability, active calls |
GET /v1/live/queues | Queues: waiting callers, longest wait, agents |
GET /v1/live/health | Service status: operational, degraded, outage |
Extension availability (availability): available, ringing, busy, on_hold, dnd, unreachable (registered but not responding), offline (no phone registered).
Events (SSE)
GET /v1/live/events keeps the connection open and sends an event for every change. On connection you receive a full snapshot, then only changes; a heartbeat every 15 seconds. With ?types= you receive only the listed types (snapshot and heartbeat are always sent).
# -N disattiva il buffer: gli eventi arrivano appena accadono
curl -N "https://centralino.exovoip.it/api/v1/live/events?types=channel.update,channel.hangup,calendar.override" \
-H "X-API-Key: $EXOPBX_API_KEY"const live = pbx.live.stream({ types: ['channel.update', 'channel.hangup', 'calendar.override'] });
live.on('snapshot', (s) => console.log('stato iniziale', s.channels.length));
live.on('channel.update', (e) => console.log(e.channel.callerNumber, e.channel.state));
live.on('calendar.override', (e) => console.log(e.name, e.forceState, e.state));
// oppure: for await (const event of live) { ... }
// live.close() per chiudere$pbx->live->stream(function (array $event): bool {
if ($event['type'] === 'channel.update') {
echo $event['channel']['callerNumber'] ?? '-', ' ', $event['channel']['state'], PHP_EOL;
}
return true; // false per fermarsi
}, ['channel.update', 'channel.hangup', 'calendar.override']);for event in pbx.live.stream(types=["channel.update", "channel.hangup", "calendar.override"]):
if event["type"] == "channel.update":
print(event["channel"]["callerNumber"], event["channel"]["state"])The SDKs reconnect automatically with increasing delays and receive a new snapshot after each reconnection: use it as the reference state instead of accumulating changes. An invalid key, or one without permissions, ends the stream without retries.
Events (WebSocket)
GET /v1/live/ws sends the same events, one per JSON message. SSE remains the recommended channel; WebSocket is useful in environments that prefer it.
# WebSocket: stessi eventi dell'SSE, un evento JSON per messaggio
websocat -H "X-API-Key: $EXOPBX_API_KEY" "wss://centralino.exovoip.it/api/v1/live/ws?types=extension.state"// Node 22+ (WebSocket globale) o browser; in Node 18/20 passare il costruttore del pacchetto ws
const ws = pbx.live.websocket({ types: ['extension.state'] });
ws.on('extension.state', (e) => console.log(e.number, e.state));In the browser, WebSocket and EventSource cannot send headers: they work with the control panel session. API keys must be used server-side only.
Event types
| Type | When |
|---|---|
snapshot | Connection or resynchronization |
channel.update | New call, state change, answer, hold, recording, bridging |
channel.hangup | End of a call (cause, duration) |
extension.state | Any extension state change |
extension.registration | First phone registered / last one disconnected |
extension.contact | Phone added, removed, reachable or unreachable |
trunk.state | Trunk registration, reachability or active calls |
queue.caller.join / queue.caller.leave | Caller enters / leaves the queue (answered, abandoned, exited) |
queue.member | Agent status or pause |
parking.update | Call parked, retrieved, timed out or abandoned |
calendar.override | Business hours override (control panel, API, phone, expiry) |
system.status | Service status change |
heartbeat | Every 15 seconds |
Platform only: system.asterisk, system.service, system.reload.
Example event:
{
"type": "calendar.override",
"tenantId": 3,
"calendarId": 4,
"name": "Ufficio",
"forceState": "closed",
"forceUntil": "2026-11-04T12:00:00.000Z",
"previousForceState": "auto",
"state": "closed"
}The full schema of each event (fields and values) is in the Swagger reference, under GET /v1/live/events.
Global view
For a global key without X-Tenant-Id (or ?tenantId=), events and snapshots cover all tenants; each object includes its tenantId.
Endpoints
| Request | Scope | SDK method |
|---|---|---|
GET /v1/live/snapshot | live:read | live.snapshot() |
GET /v1/live/channels | live:read | live.channels() |
GET /v1/live/extensions | live:read | live.extensions() |
GET /v1/live/devices | live:read | live.devices() |
GET /v1/live/trunks | live:read | live.trunks() |
GET /v1/live/queues | live:read | live.queues() |
GET /v1/live/health | live:read | live.health() |
GET /v1/live/events | live:read | live.stream() |
GET /v1/live/ws | live:read | live.websocket() (TS) |
