Visión general
La API permite iniciar llamadas Click2Call, consultar el historial de llamadas con URLs de grabación y descargar audios MP3 desde cualquier sistema externo. El flujo Click2Call es simple: la centralita llama primero al teléfono del agente (la extensión indicada) y, cuando éste descuelga, conecta automáticamente con el número de destino.
Todas las peticiones a la API requieren un Bearer token JWT que se obtiene con usuario y contraseña. Los tokens caducan a las 24 horas.
GET /api/recording/:id que devuelve audio/mpeg.
Inicio rápido
Llama a POST /api/auth/token con tus credenciales.
Llama a POST /api/call incluyendo el token en la cabecera Authorization.
La centralita llama al softphone de la extensión. Al descolgar, conecta con el destino.
Cuando recibas 401 Token expirado, repite el paso 1.
Ejemplo completo
# 1. Obtener token TOKEN=$(curl -s -X POST https://vpbx-panel-homeserve.deveco.it/api/auth/token \ -H "Content-Type: application/json" \ -d '{"username":"tu_usuario","password":"tu_contraseña"}' \ | grep -o '"access_token":"[^"]*' | cut -d'"' -f4) # 2. Iniciar llamada curl -X POST https://vpbx-panel-homeserve.deveco.it/api/call \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{"extension":"201","destination":"666123456"}'
Autenticación
Devuelve un Bearer token JWT válido durante 24 horas. No requiere ninguna cabecera de autenticación previa.
Parámetros del cuerpo
| Campo | Tipo | Descripción |
|---|---|---|
username requerido |
string | Nombre de usuario |
password requerido |
string | Contraseña |
Petición
curl -X POST https://vpbx-panel-homeserve.deveco.it/api/auth/token \ -H "Content-Type: application/json" \ -d '{"username": "tu_usuario", "password": "tu_contraseña"}'
const res = await fetch('/api/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'tu_usuario', password: 'tu_contraseña' }) }); const { access_token } = await res.json();
Respuestas
401 Token expirado,
solicita uno nuevo con este endpoint.
Usar el token
Incluye el token en la cabecera Authorization de cada petición:
Authorization: Bearer ey...
Iniciar llamada
Inicia una llamada Click2Call. La centralita marca al softphone de la extension indicada.
Cuando el agente descuelga, conecta automáticamente con destination.
Parámetros del cuerpo
| Campo | Tipo | Default | Descripción |
|---|---|---|---|
extension requerido |
string | — | Extensión SIP (Session Initiation Protocol) del agente que recibirá la llamada primero (ej. "201") |
destination requerido |
string | — | Número a marcar. Espacios, guiones y paréntesis se eliminan automáticamente; se conserva
+. |
timeout opcional |
number | 30 |
Segundos que suena el softphone del agente antes de cancelar |
autoAnswer opcional |
boolean | false |
Si true, el softphone contesta automáticamente sin que el agente descuelgue |
Petición
curl -X POST https://vpbx-panel-homeserve.deveco.it/api/call \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{ "extension": "201", "destination": "666 123 456", "timeout": 30 }'
const res = await fetch('/api/call', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${access_token}` }, body: JSON.stringify({ extension: '201', destination: '666123456' }) }); const data = await res.json();
Respuestas
callId identifica la llamada en el sistema. Guárdalo si necesitas referenciarlo
posteriormente.
Listado de llamadas
Devuelve el historial de llamadas (CDR) del periodo indicado, con una recordingUrl lista
para usar en cada llamada que tenga grabación disponible. Se pueden filtrar por extensiones concretas o
recuperar todas.
Parámetros del cuerpo
| Campo | Tipo | Default | Descripción |
|---|---|---|---|
from requerido |
string | — | Fecha de inicio del periodo, formato DD/MM/YYYY (ej. "16/01/2026").
|
to requerido |
string | — | Fecha de fin del periodo, formato DD/MM/YYYY (ej. "20/01/2026").
|
extensions opcional |
array<string> | — | Lista de extensiones a filtrar como origen (src) o destino (dst),
ej. ["201", "202"]. Si se omite, se devuelven las llamadas de
todas las extensiones. Las llamadas se deduplicarán por callId.
|
Petición
curl -X POST https://vpbx-panel-homeserve.deveco.it/api/calls \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{ "from": "16/01/2026", "to": "20/01/2026", "extensions": ["201", "202"] }'
const res = await fetch('/api/calls', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${access_token}` }, body: JSON.stringify({ from: '16/01/2026', to: '20/01/2026', extensions: ['201', '202'] }) }); const calls = await res.json();
Respuestas
En caso de éxito, devuelve un array de objetos de llamada ordenado por fecha descendente. Campos de cada objeto:
| Campo | Tipo | Descripción | Notas |
|---|---|---|---|
callId |
String | Identificador único de la llamada | |
created |
long | Fecha de la llamada | Timestamp en milisegundos desde el 1/1/1970 (GMT) |
duration |
int | Duración total de la llamada | En segundos |
billsec |
int | Duración con la llamada descolgada | En segundos |
hangupCause |
String | Causa de cuelgue | Valores posibles:NORMAL_CLEARING: Cuelgue normal; una de las partes terminó la llamadaNO_ANSWER: El destino no contestó en el tiempo límiteNO_USER_RESPONSE: El destino no respondió en absoluto (sin señal de progreso)USER_BUSY: El destino estaba ocupadoBLIND_TRANSFER: La llamada fue transferida sin consulta previa (transferencia ciega) |
type |
String | Dirección de la llamada | Valores posibles:OUTBOUND: Llamada salienteINBOUND: Llamada entrante |
dst |
String | Número de destino | |
src |
String | Número de origen | |
srcName |
String | Nombre del origen | |
did |
String | Número externo por el que entró la llamada | |
c2c |
Boolean | Si la llamada fue originada mediante Click2Call | |
c2cRequestIp |
String | IP desde la que se originó el Click2Call | |
c2cFrom |
String | Número de origen del Click2Call | |
c2cTo |
String | Número de destino del Click2Call | |
recording |
Boolean | Si hay grabación disponible | |
recordingUrl |
String | URL para descargar la grabación MP3 | null si no hay grabación. Campo añadido por este servidor. |
hangupRemote |
Boolean | Si el cuelgue lo inició el extremo remoto (el destino) | false significa que colgó el agente/extensión local |
transferUuid |
String | UUID de la llamada destino cuando se realizó una transferencia | null si la llamada no fue transferida |
outboundCid |
String | Número presentado al destino como Caller ID en llamadas salientes | Corresponde al DID (Direct Inward Dialing - número virtual utilizado para comunicaciones de larga distancia) de la extensión que originó la llamada |
remoteHeader1 |
String | Valor de una cabecera SIP (Session Initiation Protocol) personalizada enviada por el extremo remoto | null en llamadas salientes normales. Útil para integración CTI en llamadas entrantes. |
var1 – var5 |
String | Variables personalizadas asignables durante el flujo de la llamada (IVR, dialplan) | null si no se configuran en la centralita |
queueId |
String | ID de la cola | Solo si la llamada pasó por una cola |
queueWaitTime |
int | Tiempo de espera en la cola | En segundos. Solo si la llamada pasó por una cola |
queueAgent |
String | Agente que atendió la llamada | Solo si la llamada pasó por una cola |
queueCause |
String | Causa de colgado en la cola | Solo si la llamada pasó por una cola. Valores posibles:cancel: No ha sido atendido el llamanteanswered: Se ha atendido al llamante |
queueReason |
String | Razón de colgado en la cola cuando queueCause es cancel |
Solo si la llamada pasó por una cola. Valores posibles:NONE: Sin razón específicaTIMEOUT: Superado el tiempo máximo de espera en colaNO_AGENT_TIMEOUT: Superado el tiempo máximo esperando a un agenteBREAK_OUT: El llamante abandonó la cola |
recordingUrl apunta directamente al endpoint GET /api/recording/:id
de este servidor. Si la llamada no tiene grabación, el campo vale null.
Descargar grabación
Descarga el audio MP3 de una llamada grabada. El callId se obtiene del campo
callId devuelto por POST /api/calls o directamente de la
recordingUrl incluida en cada registro.
Parámetros de ruta
| Parámetro | Tipo | Descripción |
|---|---|---|
callId requerido |
string | Identificador único de la llamada (ej. abc-123-def-456) |
Petición
curl -X GET https://vpbx-panel-homeserve.deveco.it/api/recording/abc-123-def-456 \ -H "Authorization: Bearer <token>" \ --output recording.mp3
const res = await fetch('/api/recording/abc-123-def-456', { headers: { 'Authorization': `Bearer ${access_token}` } }); const blob = await res.blob(); // Reproducir directamente en el navegador const url = URL.createObjectURL(blob); const audio = new Audio(url); audio.play();
Respuestas
Content-Disposition: inline; filename="recording-{callId}.mp3", por lo que puede
reproducirse directamente en el navegador o guardarse en disco.
Listar extensiones
Devuelve un array JSON con todas las extensiones de la centralita asignada a la API Key. Los campos
sipPassword y webPassword se omiten de la respuesta.
Campos de cada objeto
| Campo | Tipo | Descripción |
|---|---|---|
id |
String | Identificador único de la extensión |
name |
String | Nombre descriptivo de la extensión |
username |
String | Número de extensión / username SIP |
type |
String | Tipo de extensión (ej. SIP) |
licenseType |
String | Tipo de licencia asignada (ej. BUSINESS) |
email |
String | Email asociado a la extensión |
domain |
String | Dominio SIP (Session Initiation Protocol) de la centralita al que debe conectarse el softphone |
cw |
Boolean | Call Waiting: si true, puede recibir llamadas mientras está ocupado |
dnd |
Boolean | Do Not Disturb: si true, rechaza todas las llamadas entrantes |
webLogin |
Boolean | Si el acceso al portal web está habilitado para esta extensión |
Petición
curl -X GET https://vpbx-panel-homeserve.deveco.it/api/extension \ -H "Authorization: Bearer <token>"
const res = await fetch('/api/extension', { headers: { 'Authorization': `Bearer ${access_token}` } }); const extensions = await res.json();
Respuestas
Buscar extensión por username
Devuelve el extensionId correspondiente al username indicado. Útil para
obtener el ID necesario para las otras operaciones sobre extensiones.
Parámetros de ruta
| Parámetro | Tipo | Descripción |
|---|---|---|
username requerido |
string | Número o nombre de usuario de la extensión (ej. 100) |
Petición
curl -X GET https://vpbx-panel-homeserve.deveco.it/api/extension/findbyusername/100 \ -H "Authorization: Bearer <token>"
const res = await fetch('/api/extension/findbyusername/100', { headers: { 'Authorization': `Bearer ${access_token}` } }); const { extensionId } = await res.json();
Respuestas
Datos de una extensión
Devuelve los datos de una extensión a partir de su id. Los campos
sipPassword y webPassword se omiten de la respuesta. Los campos devueltos
son los mismos que en GET /api/extension.
Parámetros de ruta
| Parámetro | Tipo | Descripción |
|---|---|---|
extensionId requerido |
string | Campo id devuelto por GET /api/extension |
Petición
curl -X GET https://vpbx-panel-homeserve.deveco.it/api/extension/8a9485949bd8a034019bdaf6a0d701c6 \ -H "Authorization: Bearer <token>"
const res = await fetch(`/api/extension/${extensionId}`, { headers: { 'Authorization': `Bearer ${access_token}` } }); const ext = await res.json();
Respuestas
Códigos de error
Todas las respuestas de error incluyen un campo message con la descripción del problema.
| Código | Mensaje | Qué hacer |
|---|---|---|
400 |
username y password son requeridos | Incluye ambos campos en el body de /api/auth/token |
400 |
Faltan parámetros: extension y destination son requeridos | Incluye extension y destination en el body de /api/call
|
400 |
Los campos from y to son obligatorios (formato DD/MM/YYYY, ej: 15/03/2026) | Incluye ambos campos en el body de /api/calls |
400 |
Formato de fecha inválido. Usa DD/MM/YYYY (ej: 15/03/2026) | Verifica que el formato sea exactamente DD/MM/YYYY con día, mes y año válidos |
401 |
Credenciales inválidas | Comprueba usuario y contraseña |
401 |
Token requerido | Añade la cabecera Authorization: Bearer <token> |
401 |
Token expirado | Solicita un token nuevo con POST /api/auth/token |
401 |
Token inválido | El token está malformado. Solicita uno nuevo. |
404 |
Grabación no encontrada | El callId no existe o la llamada no tiene grabación asociada |
500 |
Error al iniciar la llamada | Error interno o de conexión con la centralita. Inténtalo de nuevo o contacta con soporte. |
500 |
Error al obtener el listado de llamadas | Error interno o de conexión con la centralita al consultar el CDR. Inténtalo de nuevo. |
500 |
Error al obtener las extensiones | Error interno o de conexión con la centralita al consultar /api/extension. Inténtalo de nuevo. |
500 |
Error al actualizar la extensión | Error interno o de conexión con la centralita. Inténtalo de nuevo. |
502 |
Respuesta inesperada | La centralita devolvió un formato no esperado. Contacta con soporte si persiste. |