API de Marcación Predictiva
Detección de contestadora y bridge
automático a un agente
Guía de integración para que un sistema de discado predictivo dispare llamadas salientes, valide con AMD que contesta una persona (no un buzón) y las conecte de inmediato con un agente WebRTC.
Resumen del servicio
El sistema del cliente envía una solicitud HTTP por cada contacto a marcar. Voz MX origina la llamada saliente, corre un análisis automático de contestadora (AMD) sobre el audio de respuesta y, si confirma que contestó una persona, conecta la llamada de inmediato con la extensión del agente indicada. Si contesta un buzón o nadie responde, la llamada se cierra y se reporta el resultado — el servicio no reintenta la marcación; los reintentos, si se requieren, los gestiona el sistema del cliente.
Endpoint y autenticación
Toda solicitud se autentica con una llave fija enviada en el encabezado
X-API-Key, provista por Voz MX de forma independiente a este documento.
Solicitud
POST https://pbx.vozmx.mx/api/call Content-Type: application/json X-API-Key: <llave asignada>
Parámetros de la solicitud
| Campo | Tipo | Uso | Descripción |
|---|---|---|---|
tel | string | obligatorio | Número a marcar — 10 dígitos, sin lada de país ni separadores. |
extension | string | obligatorio | Extensión WebRTC del agente destino, asignada por Voz MX. |
ring_timeout | number | opcional | Segundos de timbrado antes de reportar no-contestado. Rango 5–120, por defecto 45. Conviene subirlo para números celulares. |
mode | string | opcional | "sync" o "async". Si se omite, se usa el modo por defecto configurado del lado de Voz MX. Ver sección 05. |
callback_url | string | opcional | URL propia de esta llamada para recibir el resultado. Obligatoria si mode es "async" y no hay una callback_url global configurada en el servidor. |
Ejemplo — síncrono
{
"tel": "5551234567",
"extension": "602611",
"ring_timeout": 60
}
Ejemplo — asíncrono con callback propio
{
"tel": "5551234567",
"extension": "602611",
"mode": "async",
"callback_url": "https://cliente.example.com/webhook/resultado"
}
Comportamiento del flujo
- Se recibe la solicitudVoz MX valida la llave, el número y la extensión, y origina la llamada saliente hacia
tel. - Se analiza la respuestaAl contestar, corre la detección de contestadora (AMD) sobre los primeros segundos de audio.
- Bifurcación según resultadoSi el análisis confirma una persona, la llamada se conecta de inmediato con la extensión del agente. Si detecta buzón, o el resultado es ambiguo, o nadie contesta, la llamada se cuelga — sin reintento.
- Se reporta el resultadoEn modo síncrono, la respuesta HTTP se entrega hasta conocer el desenlace. En modo asíncrono, se confirma la recepción de inmediato y el resultado llega después a
callback_url.
Modo de respuesta
mode: "sync" (default)
Síncrono
El POST permanece abierto hasta que se conoce el resultado final y responde con el JSON de desenlace en la misma conexión.
mode: "async"
Asíncrono
Responde de inmediato con 202 y un call_id; el resultado se entrega después vía POST a callback_url.
El modo se elige por solicitud con el campo mode del JSON — si se omite,
se usa el default configurado del lado de Voz MX. Si el volumen de marcación es
alto, se recomienda pedir modo asíncrono para no mantener conexiones HTTP abiertas por
cada llamada en curso.
Formato de la respuesta
JSON — mismo formato en ambos modos
{
"call_id": "51d18c42-8700-…",
"tel": "5551234567",
"extension": "602611",
"status": "connected",
"amd_status": "HUMAN"
}
| status | Significado |
|---|---|
| connected | Contestó una persona y se conectó con el agente. |
| no_human | Contestó, pero se detectó buzón o el resultado fue ambiguo — se colgó. |
| failed | La llamada terminó antes de completarse (colgó el destino, nadie contestó, error de red). |
| timeout | No se obtuvo un resultado dentro del tiempo máximo de espera. |
Errores
| HTTP | Causa |
|---|---|
401 | X-API-Key ausente o incorrecto. |
400 | tel no son 10 dígitos, extension no es válida, ring_timeout fuera del rango 5–120, mode distinto de "sync"/"async", o mode: "async" sin callback_url (propia ni global). |
409 | La extension no está registrada en el PBX en ese momento: el agente debe registrar su softphone antes de recibir llamadas. No se marca al cliente. |
502 | No fue posible originar la llamada por una condición interna de la plataforma. |
Verificación de disponibilidad
Para monitoreo del servicio, sin autenticación:
GET https://pbx.vozmx.mx/api/health → {"status": "ok"}
Crear una campaña
Antes de subir contactos hace falta una campaña. Se puede crear desde el panel
pbx.vozmx.mx/predictivo
o directamente por API — útil si el sistema del cliente da de alta campañas de forma
automática. La creación es idempotente por nombre: si ya existe una
campaña con ese name, no se crea una segunda — se regresa la existente con
su configuración actual, así que este mismo endpoint también sirve para consultar
"¿ya existe esta campaña? ¿con qué parámetros quedó?" antes de decidir si crear una nueva.
Solicitud (todos los campos excepto name son opcionales)
POST https://pbx.vozmx.mx/api/campaigns X-API-Key: <llave asignada> Content-Type: application/json { "name": "Campaña Octubre", "agent_strategy": "longest_idle", "agents": ["602611", "602612"], "dial_ratio": 1.0, "target_abandon_rate": 3.0, "ring_timeout_seconds": 30, "wrap_up_seconds": 30, "max_attempts": 3, "retry_delay_minutes": 60, "calling_hours_start": "09:00:00", "calling_hours_end": "20:00:00" }
| Campo | Tipo | Descripción |
|---|---|---|
name | string | obligatorio — identifica la campaña; si ya existe una con este nombre, se regresa esa en vez de crear otra. |
agent_strategy | string | "longest_idle" (default, el agente libre hace más tiempo entra primero) o "round_robin". |
agents | array | Extensiones asignadas: 602611–602614, o 602620 de pruebas. |
dial_ratio | number | Llamadas por agente libre al iniciar (default 1.0); el motor lo ajusta solo mientras corre. |
target_abandon_rate | number | % de abandono objetivo (default 3.0). |
ring_timeout_seconds | number | Timeout de timbrado (default 30). |
wrap_up_seconds | number | Tiempo de documentación post-llamada (default 30): el agente no recibe la siguiente llamada hasta que pasa este tiempo después de colgar. 0 lo desactiva. |
max_attempts | number | Intentos máximos por contacto (default 3). |
retry_delay_minutes | number | Minutos de espera entre reintentos (default 60). |
calling_hours_start / calling_hours_end | string | Horario de marcado, formato HH:MM:SS (default 09:00–20:00). |
Respuesta — campaña nueva (código 201)
{
"exists": false,
"campaign": { "id": 7, "name": "Campaña Octubre", "status": "draft", "...": "resto de los parámetros" },
"assignedAgents": ["602611", "602612"]
}
Respuesta — la campaña ya existía (código 200)
{
"exists": true,
"campaign": { "...": "su configuración actual" },
"assignedAgents": ["602611", "602612"],
"stats": [ { "status": "pending", "total": 40 } ]
}
| HTTP | Causa |
|---|---|
401 | X-API-Key ausente o incorrecto. |
400 | Falta name, agent_strategy no es válido, o agents trae una extensión que no existe. |
Alta de contactos por campaña
Además de originar llamadas una por una con /api/call, Voz MX opera un
motor propio de marcación predictiva (pacing y asignación automática de agente) que
trabaja por campañas. Las campañas se crean y administran desde el panel
pbx.vozmx.mx/predictivo
(acceso provisto por Voz MX de forma independiente a este documento); al crear o abrir
una campaña ahí, su ID aparece visible en la parte superior de su detalle
— ese es el que se usa en la solicitud de abajo. Una vez con el ID, el sistema del cliente
puede subir o ampliar la lista de contactos directamente por API, en el formato que le
resulte más cómodo.
Solicitud
POST https://pbx.vozmx.mx/api/campaigns/<id>/contacts X-API-Key: <llave asignada>
Acepta tres formatos de entrada, según convenga:
a) JSON
Content-Type: application/json { "contacts": [ { "phone": "5551234567", "name": "Juan Pérez" }, "5559876543" ] }
Cada elemento de contacts puede ser un objeto (phone/telefono
+ name/nombre opcional) o un número suelto, sin nombre.
b) CSV o c) Excel (.xlsx / .xls)
Content-Type: multipart/form-data campo: file=<lista.csv | lista.xlsx>
Encabezados reconocidos: telefono/phone/numero/tel
y nombre/name (sin importar mayúsculas). Sin encabezado
reconocible, se toma la primera columna como teléfono y la segunda como nombre. Se
aceptan números a 10 dígitos, o a 12 con lada país 52 al frente. Las filas
con teléfono inválido se ignoran — no truena la subida completa.
Respuesta exitosa — 201
{ "inserted": 3 }
| HTTP | Causa |
|---|---|
401 | X-API-Key ausente o incorrecto. |
404 | El ID de campaña no existe. |
400 | Archivo en formato no soportado, o ningún número válido en la solicitud. |
Reportes de campaña
Toda la información visible en el panel /predictivo también está disponible por
API, para integrarla a un sistema propio de reportes sin depender de la sesión web.
Listar campañas
GET https://pbx.vozmx.mx/api/campaigns X-API-Key: <llave asignada>
Detalle de una campaña (agentes asignados con registered en vivo + estadísticas por estado)
GET https://pbx.vozmx.mx/api/campaigns/<id>
Reporte de contactos (filtrable y paginado)
GET https://pbx.vozmx.mx/api/campaigns/<id>/contacts?status=no_answer&page=1
| Parámetro | Valores |
|---|---|
status | dialed (default, todos los ya marcados), pending, dialing, machine, no_answer, failed, dnc, completed |
page | Número de página, 100 contactos por página (default 1) |
Respuesta
{
"filter": "no_answer",
"page": 1,
"totalPages": 1,
"total": 4,
"contacts": [
{ "id": 8, "phone": "8115167260", "name": "Horacio Frias", "status": "no_answer", "attempts": 1, "last_attempt_at": "2026-08-27 12:02:21" }
]
}
Reencolar y controlar la campaña
Los contactos que no se completaron con éxito (no contestó, contestadora, falló) se pueden regresar a la cola de marcado — el motor los vuelve a tomar como pendientes en su siguiente ciclo, respetando el ratio y el horario configurado de la campaña.
Reencolar todos los que coincidan con un estado
POST https://pbx.vozmx.mx/api/campaigns/<id>/requeue Content-Type: application/json { "status": "no_answer" }
Reencolar solo contactos específicos
{ "contact_ids": [8, 11, 13] }
Si se envían ambos, contact_ids tiene prioridad. Respuesta: { "requeued": <número de contactos afectados> }.
Control de la campaña
POST https://pbx.vozmx.mx/api/campaigns/<id>/start POST https://pbx.vozmx.mx/api/campaigns/<id>/pause POST https://pbx.vozmx.mx/api/campaigns/<id>/stop
start pone la campaña en marcha y marca disponibles a los agentes asignados
que estén registrados en el PBX;
pause detiene la generación de llamadas nuevas sin colgar las que ya están en
curso; stop detiene la campaña y libera a sus agentes.
Disponibilidad de agentes = registro SIP
No hay que avisar al PBX que un agente está listo: una extensión
entra a la rotación en cuanto su softphone se registra y sale en cuanto se desregistra
(el motor lo revisa cada 3 s). Si ninguna extensión asignada está registrada, la campaña
queda en running pero no marca hasta que alguien se registre. La respuesta de
start trae agents_registered y agents_unregistered, y
el detalle de la campaña trae registered por agente, para comprobarlo antes de arrancar.
Inactivar y reactivar una campaña
POST https://pbx.vozmx.mx/api/campaigns/<id>/deactivate POST https://pbx.vozmx.mx/api/campaigns/<id>/activate GET https://pbx.vozmx.mx/api/campaigns?include_inactive=1
Una campaña no se borra: se inactiva. deactivate la saca del
listado y del motor de marcado, pero conserva sus contactos, intentos e historial de
llamadas. Solo se acepta con la campaña detenida (draft,
stopped o completed); si sigue running o
paused responde 409 — primero stop, nunca en caliente.
activate la regresa a stopped, lista para editarse o iniciarse.
El listado GET /api/campaigns omite las inactivas salvo con
include_inactive=1, y una campaña inactiva ya no cuenta para la idempotencia
por nombre: se puede crear una nueva con el mismo name.
Respuesta: { "status": "inactive", "campaign": { … } }.
| HTTP | Causa |
|---|---|
401 | X-API-Key ausente o incorrecto. |
404 | El ID de campaña no existe. |
400 | En requeue: falta status/contact_ids, o status no es uno de los valores válidos. |
409 | En deactivate: la campaña sigue running/paused (haz stop primero). En start/pause/stop: la campaña está inactiva (haz activate primero). |