Base · https://tu-servidor.neervox.com/api/externo/v1

Integra tu CRM con el IVR de NeervoX

Una API REST para lanzar campañas de voz masivas, cargar contactos con sus datos y recuperar el resultado de cada llamada — todo desde tu propio sistema, sin que nadie entre a la interfaz.

32 endpoints Autenticación por llave Respuestas en JSON Hasta 250.000 contactos por carga

Qué es esta API

El IVR de NeervoX marca miles de teléfonos por hora y reproduce un mensaje de voz. Esta API deja que tu CRM opere ese motor: crear la campaña, cargar a quién llamar con el RUT y los datos que quieras, arrancarla, y después leer cómo terminó cada llamada para cruzarla contra tu base.

Todo se hace con peticiones HTTP a la URL base. Cada respuesta es JSON. No hay SDK que instalar: sirve curl, fetch, la librería HTTP de tu lenguaje o cualquier cliente REST.

URL base
tu-servidor.neervox.com/api/externo/v1
Protocolo
HTTPS · REST · JSON
Autenticación
Cabecera X-API-Key
Zona horaria
Configurable · fechas en ISO 8601 UTC

Autenticación

Cada petición lleva tu llave de API en la cabecera X-API-Key. Sin ella la respuesta es 401.

La llave la genera un administrador desde la interfaz de NeervoX (sección Integraciones). Se muestra una sola vez al crearla — guárdala en un lugar seguro; en el servidor solo queda su huella, así que si se pierde hay que generar otra.

Dos niveles de permiso

PermisoPuedeNo puede
lectura Consultar campañas, reportes, salud de carriers, listas, resultados. Crear, modificar, cargar contactos, arrancar ni detener.
escritura Todo lo de lectura, más crear campañas, cargar contactos, arrancar, detener, subir audios. Administrar llaves (eso es solo desde la interfaz).

Una llave de solo lectura que intente escribir recibe 403. Da a cada integración el permiso mínimo que necesita.

# Toda petición lleva la llave en la cabecera
curl https://tu-servidor.neervox.com/api/externo/v1/ping \
  -H "X-API-Key: nvx_a1b2c3d4e5f6..."

Tu primera llamada

El endpoint /ping confirma que la llave sirve. Es lo primero que conviene probar al integrar.

GET /ping lectura
curl https://tu-servidor.neervox.com/api/externo/v1/ping \
  -H "X-API-Key: TU_LLAVE"

# Respuesta 200
{
  "ok": true,
  "servicio": "IVR NeervoX",
  "momento": "2026-09-16T01:31:20.221Z"
}

Si en vez de eso recibes 401 Unauthorized, la llave falta o es incorrecta. Si recibes 403 Forbidden, la llave existe pero no tiene el permiso que ese endpoint exige.

Errores y límites

La API usa los códigos HTTP estándar. El cuerpo de un error trae siempre un message legible que explica qué pasó.

CódigoSignificaQué hacer
200 / 201Todo salió bien.
400Algo en la petición está mal (falta un campo, un formato inválido, una lista vacía).Lee el message: dice exactamente qué corregir.
401Falta la llave o es inválida.Revisa la cabecera X-API-Key.
403La llave no tiene permiso de escritura.Usa una llave de escritura para ese endpoint.
404El recurso (campaña, lista…) no existe.Verifica el id.
500Error interno. Queda registrado del lado del servidor.Reintenta; si persiste, reporta el momento exacto.

Ejemplo de error

# 400 al cargar una lista sin números utilizables
{
  "message": "Ninguno de los números recibidos es utilizable.",
  "error": "Bad Request",
  "statusCode": 400
}

Límites

  • Hasta 250.000 contactos por carga (unas 12 MB con RUT). Para más, divide en varias cargas usando el mismo lista_id: se suman a la misma lista.
  • El cuerpo de la petición admite hasta 25 MB.
  • Los teléfonos y RUT se normalizan solos: un 912345678 se guarda como 56912345678, y el RUT se valida con su dígito verificador.

Flujo completo de una integración

El caso típico: tu CRM crea una campaña, le carga a quién llamar, la arranca y después lee el resultado. Cinco pasos.

  1. Elegir un árbol de voz

    Una campaña necesita un árbol publicado (el mensaje que se reproduce). Lístalos y guarda el id del que vas a usar.

    GET/arboleslectura
  2. Crear la campaña

    Queda en borrador (DRAFT): no hace sonar ningún teléfono hasta que le cargues números y la arranques. Es deliberado — evita un envío por accidente.

    POST/campanasescritura
    {
      "nombre": "Cobranza septiembre",
      "flow_id": "<id del árbol>",
      "max_channels": 300,
      "cps": 10,
      "max_intentos": 2,
      "espera_reintento_min": 180,
      "hora_inicio_diaria": "09:00",
      "hora_fin_diaria": "19:00"
    }
  3. Cargar los contactos

    Manda el teléfono con los datos que quieras recuperar después (RUT, nombre, lo que traiga tu base). Se descartan solos los repetidos, los que no parecen teléfono, los que ya se sabe que no existen y los que pidieron no ser llamados.

    POST/campanas/{id}/contactos-con-datosescritura
  4. Revisar y arrancar

    Antes de arrancar puedes ver una muestra de lo que va a discar con GET /campanas/{id}/muestra. Cuando estés listo, arráncala: a partir de aquí suenan teléfonos de verdad.

    POST/campanas/{id}/arrancarescritura
  5. Leer el resultado

    Mientras disca, consulta el avance con /campanas/{id}/reporte. Al terminar, baja el resultado llamada por llamada — cada uno trae de vuelta el RUT y los datos que mandaste, para cruzar contra tu CRM.

    GET/campanas/{id}/resultadoslectura
Estados de una campaña. Sigue este ciclo: DRAFT (recién creada, no disca) → RUNNING (discando) → PAUSED (detenida, se retoma donde iba) → DONE (terminó). Detener y volver a arrancar es seguro: lo pendiente se retoma.

Cargar contactos con datos

La forma útil para un CRM: cada teléfono viaja con un objeto extra — RUT, nombre, deuda, lo que sea — que vuelve intacto junto al resultado de la llamada.

POST /campanas/{id}/contactos-con-datos escritura
curl -X POST https://tu-servidor.neervox.com/api/externo/v1/campanas/{id}/contactos-con-datos \
  -H "X-API-Key: TU_LLAVE" \
  -H "Content-Type: application/json" \
  -d '{
    "lista": "Morosos septiembre",
    "contactos": [
      { "numero": "912345678", "extra": { "rut": "12345678-5", "nombre": "Juan Pérez" } },
      { "numero": "987654321", "extra": { "rut": "9876543-3", "deuda": "45000" } }
    ]
  }'

# Respuesta 201 — cada descarte dice POR QUÉ
{
  "recibidos": 2,
  "cargados": 2,
  "repetidos": 0,
  "no_parecen_numero": 0,
  "ya_estaban": 0,
  "no_existen": 0,
  "dados_de_baja": 0,
  "lista": { "id": "a1b2...", "nombre": "Morosos septiembre" }
}

Listas dentro de una campaña

Cada carga es una lista con nombre propio. Todas comparten el árbol, el carrier y el horario de la campaña, pero se pueden pausar y medir por separado. Para sumar contactos a una lista que ya existe, manda su lista_id en vez de lista.

Los datos que mandas en extra vuelven en datos al leer los resultados. Ese es el punto de todo esto: cruzar la gestión contra tu propia base sin buscar número por número.

Leer los resultados

Cada fila es un intento, no una persona: si a alguien se le llamó dos veces, aparecen sus dos llamadas con su número de intento. Los datos que cargaste vuelven en datos.

GET /campanas/{id}/resultados lectura

Acepta ?desde= (fecha ISO, para traer solo lo nuevo desde tu última consulta), ?limite= (máximo 2000) y ?detalle=1 (agrega códigos de cuelgue, calidad, recorrido por el árbol y las columnas de tu Excel).

# Sondeo incremental: cada X minutos, trae lo nuevo
curl ".../campanas/{id}/resultados?desde=2026-09-16T00:00:00Z&detalle=1" \
  -H "X-API-Key: TU_LLAVE"

# Respuesta 200 — un objeto por intento
[
  {
    "numero": "56912345678",
    "contesto": true,
    "resultado": "COMPLETED",
    "duracion_seg": 30,
    "escucho_completo": true,
    "audio_segundos": 30,
    "teclas": null,
    "transferida": false,
    "pidio_baja": false,
    "momento": "2026-09-16T13:10:28.796Z",
    "datos": { "rut": "12345678-5", "nombre": "Juan Pérez" }
  }
]
Sondeo, no webhook. Hoy los resultados se consultan por polling: pregunta cada pocos minutos con ?desde= apuntando a tu última lectura, y procesa solo lo nuevo. Guarda el momento del último registro que viste para la próxima consulta.

No molestar

Quien pidió no ser llamado no debe recibir llamadas — vengan de donde vengan. La API respeta esa lista en toda carga y te deja consultarla y alimentarla.

GET/bajas/{numero}lectura

Consulta si un número pidió no ser llamado, antes de cargarlo.

POST/bajasescritura

Registra una baja que recibiste por otro canal (tu call center, tu web). Cuerpo: { "numero": "...", "motivo": "..." }.

No hace falta que filtres tú las bajas antes de cargar: al cargar contactos, los que están en la lista de No Molestar se descartan solos y se reportan en dados_de_baja.

Referencia · Campañas

GET/campanaslectura

Todas las campañas, con estado, avance y contadores. Es de donde tu CRM saca los id.

[
  {
    "id": "c3a1f0e2-...",
    "nombre": "Campaña de ejemplo",
    "estado": "DONE",
    "arbol": "Árbol de ejemplo",
    "cargados": 50000,
    "discadas": 50000,
    "contestadas": 11500,
    "pendientes": 0,
    "creada": "2026-01-15T09:00:00.000Z"
  }
]
GET/campanas/{id}lectura

Estado de una campaña: cargados, discadas, contestadas, pendientes.

POST/campanasescritura

Crea una campaña (queda en DRAFT). Requiere nombre y flow_id; el resto es opcional con valores por defecto sensatos.

PATCH/campanas/{id}escritura

Cambia ritmo, horario, carrier o árbol. Se aplica en la vuelta siguiente, sin detener la campaña.

POST/campanas/{id}/arrancarescritura
POST/campanas/{id}/detenerescritura

arrancar hace sonar teléfonos de verdad. detener pausa; lo pendiente se retoma donde iba.

GET/campanas/{id}/muestralectura

Qué va a discar exactamente, para revisarlo antes de arrancar. Acepta ?limite=.

GET/campanas/{id}/en-vivolectura

Cómo va ahora mismo: en curso, pendientes, últimas llamadas.

Referencia · Contactos y listas

POST/campanas/{id}/contactos-con-datosescritura

Carga contactos con su objeto extra. La forma recomendada para un CRM. Ver detalle arriba →

POST/campanas/{id}/contactosescritura

Carga simple, solo teléfonos: { "numeros": ["912345678", ...] }. Hasta 250.000 por llamada.

GET/campanas/{id}/listaslectura

Las cargas de la campaña. llamados = recibieron al menos una llamada (aunque esperen un reintento); cerrados = a los que ya no se llamará más.

POST/campanas/{id}/listasescritura

Crea una lista vacía para cargarle números después: { "nombre": "Lote A" }.

PATCH/listas/{listaId}escritura

Pausa o reanuda una lista: { "activa": false }. Pausar no borra: los números y su historial quedan.

Referencia · Reportes

Los mismos datos que ve la interfaz. Cada porcentaje viene con la base sobre la que está calculado — "25%" no significa lo mismo sobre lo cargado que sobre lo efectivamente llamado.

GET/operacionlectura

Lo que pasa ahora en todas las campañas: en curso, ritmo, consolidado del día.

GET/operacion/por-horalectura

Cómo se repartió la jornada de hoy, hora a hora.

GET/campanas/{id}/reportelectura

Resumen con cada tasa y su base: contacto, cobertura, avance, reintentos.

{
  "cargados": 50000,
  "discadas": 50000,
  "intentos": 72000,
  "reintentos": 22000,
  "contestadas": 11500,
  "tasas": {
    "contacto":  { "valor": 23, "sobre": "personas llamadas" },
    "cobertura": { "valor": 23, "sobre": "contactos cargados" }
  }
}
GET/campanas/{id}/reporte/supervisorlectura

El reporte operativo: quién cortó primero, cuánto del mensaje se escuchó, rendimiento por intento, tiempo hasta contestar y motivos de no-contacto.

GET/campanas/{id}/reporte/teclaslectura
GET/campanas/{id}/reporte/embudolectura
GET/campanas/{id}/reporte/por-horalectura

Qué tecla marcó la gente; por dónde pasó dentro del árbol y dónde se fue cayendo; comportamiento hora a hora.

GET/reportes/compararlectura

Campañas lado a lado: cuál rindió mejor. Acepta ?minimo= (excluye campañas con pocas llamadas).

Referencia · Salud de carriers

GET/carriers/saludlectura

Cómo responde cada carrier ahora mismo: estado (SANO/ALERTA/CAIDO/SIN_DATOS), tasa de contacto y duración media.

GET/carriers/historicolectura

El acumulado de cada carrier en el periodo, con su día a día. Acepta ?dias= (por defecto 30).

GET/carriers/{id}/tendencialectura

La serie de un carrier: la tendencia dice más que el momento. Acepta ?dias=.

Referencia · Audios y árboles

GET/arboleslectura

Los árboles de voz disponibles, para elegir con cuál disca una campaña.

GET/arboles/{id}lectura

Un árbol con sus nodos y conexiones.

GET/audioslectura

Los audios disponibles para usar en un árbol.

POST/audiosescritura

Sube un audio (multipart/form-data, campo file). Se convierte al formato que la central necesita — subirlo crudo dejaría la llamada muda, así que la conversión no es opcional.

Todos los endpoints

Los 32 endpoints de la v1, de un vistazo.

Método y rutaQué hacePermiso
GET/pingComprueba la llavelectura
GET/campanasLista campañaslectura
GET/campanas/{id}Estado de una campañalectura
POST/campanasCrea campaña (queda en borrador)escritura
PATCH/campanas/{id}Cambia ritmo, horario, carrier, árbolescritura
POST/campanas/{id}/arrancarEmpieza a discarescritura
POST/campanas/{id}/detenerPausa la campañaescritura
GET/campanas/{id}/muestraQué va a discar (antes de arrancar)lectura
GET/campanas/{id}/en-vivoCómo va ahora mismolectura
POST/campanas/{id}/contactos-con-datosCarga contactos con RUT y datosescritura
POST/campanas/{id}/contactosCarga solo teléfonosescritura
GET/campanas/{id}/listasLas cargas de la campañalectura
POST/campanas/{id}/listasCrea una lista vacíaescritura
PATCH/listas/{listaId}Pausa o reanuda una listaescritura
GET/campanas/{id}/resultadosResultado llamada por llamadalectura
GET/bajas/{numero}¿Pidió no ser llamado?lectura
POST/bajasRegistra una bajaescritura
GET/operacionPanorama en vivolectura
GET/operacion/por-horaLa jornada de hoy, hora a horalectura
GET/campanas/{id}/reporteResumen con tasas y baseslectura
GET/campanas/{id}/reporte/supervisorReporte operativo detalladolectura
GET/campanas/{id}/reporte/teclasQué tecla marcó la gentelectura
GET/campanas/{id}/reporte/embudoRecorrido por el árbollectura
GET/campanas/{id}/reporte/por-horaComportamiento hora a horalectura
GET/reportes/compararCampañas lado a ladolectura
GET/carriers/saludEstado de cada carrier ahoralectura
GET/carriers/historicoAcumulado del periodo, día a díalectura
GET/carriers/{id}/tendenciaLa serie de un carrierlectura
GET/arbolesÁrboles de voz disponibleslectura
GET/arboles/{id}Un árbol con sus nodoslectura
GET/audiosAudios disponibleslectura
POST/audiosSube un audioescritura