Download OpenAPI specification:Download
Integración de la Centralita Virtual con su propio servidor: cuando alguien llama a uno de sus números de voz, hacemos una petición POST (JSON, firmada) a la URL que usted configure y ejecutamos en la llamada la acción que su servidor responda: hablar con el asistente de IA, reproducir un texto, desviar a un teléfono/extensión/grupo, ofrecer un menú de opciones, buzón de voz o colgar.
De esta forma su propia lógica de negocio decide, en tiempo real y llamada a llamada, qué hacer con cada llamante: enrutar por cliente VIP, por horario propio, por estado de un pedido, identificar al llamante contra su CRM, etc.
En su panel: Voz → Recepción de llamadas, seleccione el número y elija «Preguntar a mi servidor (integración por URL)». Configure:
- URL de su servidor: debe ser https y un host público (no se admiten IPs privadas ni redirecciones).
- Tiempo máximo de espera: 2 a 8 segundos. La llamada está sonando mientras su servidor responde: responda lo más rápido posible.
- Acción por defecto: qué hacemos si su servidor no responde a tiempo, devuelve un error o un JSON inválido. Puede ser cualquiera de las acciones de la centralita: asistente de IA, menú de opciones, desvío a un teléfono, a una extensión o a un grupo de salto, aplicar un escenario guardado (la llamada hace exactamente lo que ese escenario tenga configurado), buzón o colgar.
- Clave de verificación: se genera al guardar; con ella firmamos cada petición para que pueda comprobar que somos nosotros.
El botón Probar del panel lanza una petición de prueba real contra su URL y le muestra el diagnóstico (código HTTP, JSON recibido y acción que se ejecutaría).
Cada petición incluye la cabecera X-Mensatek-Signature con el HMAC-SHA256 (en hexadecimal) del cuerpo crudo de la petición, calculado con su clave de verificación:
X-Mensatek-Signature: sha256=HMAC_SHA256(cuerpo, clave)
Ejemplo de verificación en PHP:
$clave = 'SU_CLAVE_DE_VERIFICACION';
$cuerpo = file_get_contents('php://input');
$firma = $_SERVER['HTTP_X_MENSATEK_SIGNATURE'] ?? '';
if (!hash_equals('sha256='.hash_hmac('sha256', $cuerpo, $clave), $firma)) {
http_response_code(401); exit;
}
$datos = json_decode($cuerpo, true);
Recomendamos rechazar (401) cualquier petición cuya firma no verifique.
Si su servidor no responde dentro del tiempo configurado, responde con un código distinto de 2xx o el cuerpo no es un JSON válido, la llamada no se pierde: se ejecuta automáticamente la acción por defecto configurada en su panel. Su servidor debe responder 2xx con Content-Type: application/json.
Responda un objeto JSON con el campo accion y los campos adicionales que apliquen a esa acción (los demás se ignoran):
| accion | Qué hace | Campos adicionales |
| `ia` | El llamante conversa por voz con su asistente de IA (el mismo que entrena para WhatsApp). Es también la acción si accion se omite o no se reconoce. | `texto` (opcional): sustituye el saludo inicial. |
| `reproducir` | Lee el texto por voz y cuelga. | `texto` (recomendado; si se omite se lee «Gracias por su llamada.»). |
| `desviar` | Transfiere la llamada al destino indicado. | `destino` (obligatorio): teléfono nacional español o internacional +E164, ext:NNN (extensión de su centralita) o grupo:N (grupo de salto). Los números 90x/80x están bloqueados; un destino inválido cae al asistente de IA. |
| `ivr` | Ofrece un menú de opciones (teclas y palabras por voz). | `plantilla`: nombre de un menú guardado en su panel; o `menu`: objeto de menú en línea (ver formato abajo). Si ninguno es válido, cae al asistente de IA. |
| `buzon` | Locución y buzón de voz (el audio le llega por email). | `texto` (opcional): aviso antes de la señal. |
| `buzon_inteligente` | Buzón inteligente: pide al llamante su email por voz (se transcribe y se normaliza «arroba/punto», sin hacerle confirmar: dictar un correo por teléfono cansa y hace que cuelgue sin dejar el recado), le consulta a usted con el evento `buzon_email`, pide el motivo —que es lo importante, junto con su teléfono—, lo transcribe y, al despedirse, le ofrece repetir el correo por si no era ese. Todo se envía por correo al titular con el audio de la llamada adjunto, para poder comprobar la dirección si la transcripción no fue fina. | `texto` (opcional): locución de apertura. |
| `colgar` | Cuelga la llamada. | `texto` (opcional): despedida antes de colgar. |
Campos comunes opcionales, aplicables a cualquier acción:
- idioma: voz e idioma del TTS con el formato xx-XX:n (n: 1 mujer, 2 hombre). Ej.: es-ES:1, pt-PT:1, en-US:1.
- grabar: true/false, activa o desactiva la grabación de esta llamada.
Ejemplos de respuesta:
// Desviar un cliente VIP a su gestor
{ "accion": "desviar", "destino": "+34600000001" }
// Desviar al grupo de salto 2 (suena en varias extensiones)
{ "accion": "desviar", "destino": "grupo:2" }
// Saludo personalizado y asistente de IA
{ "accion": "ia", "texto": "Hola Sr. Garcia, le atiende el asistente de MiEmpresa." }
// Menu guardado en el panel
{ "accion": "ivr", "plantilla": "Menu principal" }
// Leer un aviso y colgar
{ "accion": "reproducir", "texto": "Su pedido 1234 sale hoy. Gracias por su llamada." }
// Buzon con aviso propio y grabacion activada
{ "accion": "buzon", "texto": "Ahora no podemos atenderle, deje su mensaje.", "grabar": true }
Formato del menú en línea (menu): el mismo objeto que genera el editor visual del panel. Claves: locucion (texto que se lee ofreciendo las opciones; admite los marcadores (MP3:fichero) y (PAUSA:segundos)), esMenuDTMF = 1, y una clave por tecla con la opción: Accion (1 repetir · 2 aviso a URL · 3 aviso por email · 4 transferir a teléfono · 6 colgar · 7 asistente de IA · 8 transferir a extensión · 9 transferir a grupo), Valor (destino de la acción), Palabra (opcional: el llamante puede DECIRLA en vez de pulsar), LocucionPrevia y LocucionFinal (opcionales, antes y después de la acción).
{
"accion": "ivr",
"menu": {
"locucion": "Para comercial, diga comercial o pulse 1. Para soporte, pulse 2.",
"esMenuDTMF": 1,
"1": { "Accion": "9", "Valor": "grupo:1", "Palabra": "comercial", "LocucionPrevia": "Le paso con comercial." },
"2": { "Accion": "8", "Valor": "ext:102" }
}
}
El campo evento de la petición identifica el momento de la llamada en que le consultamos (ignore los eventos que no reconozca respondiendo su acción por defecto):
| evento | Cuándo se envía | Campos adicionales de la petición |
| `llamada_entrante` | Acaba de recibirse la llamada en su número. | `idcliente`, si quien llama es un contacto con identificador de cliente guardado (así reconoce a un cliente de siempre que llama desde otro teléfono). |
| `consulta_contacto` | Un agente pulsa la varita al dar de alta un contacto, en el panel o en la app. No hay llamada: responda solo con el objeto `contacto` (nombre, apellidos, email, idcliente…), o con `{}` si no lo encuentra. Lo que devuelva rellena la ficha que el agente está creando, y el `idcliente` queda guardado con el contacto. | `idcliente` o `email` (el dato por el que se pregunta), `telefono` (el del contacto que se está creando) y `numero`/`to` (su número cuya URL se usa: con él sabe con qué clave viene firmada la petición). |
| `sin_respuesta` | La llamada se desvió a un grupo de salto con cola de espera y nadie la atendió tras agotar los avisos configurados. Su respuesta decide qué hacer con la llamada; si no responde (o responde algo inválido), se aplica el destino final del grupo. | `grupo` (id del grupo, entero) y `avisos` (avisos de espera reproducidos, entero). |
| `buzon_email` | El buzón inteligente ha capturado el email del llamante (transcrito, sin confirmar: puede llevar erratas). Su respuesta puede incluir `contacto` (los datos del llamante según su CRM: se adjuntan al correo que recibirá el titular) y `texto` (la locución con la que pedir el motivo de la consulta). El campo `accion` se ignora en este evento. | `email` (el capturado; el llamante puede corregirlo al final de la llamada). |
La especificación irá incorporando nuevos eventos manteniendo el mismo formato y firma.
Un escenario es una combinación de «qué hace la llamada» guardada en el panel con un nombre y una clave: modo de entrada, saludo, menú, desvío, música de espera, grabación, encuesta y buzón. Se guardan desde Recepción de llamadas (botón Guardar como escenario) y su servidor los aplica devolviendo solo su clave:
{ "escenario": "soporte-vip" }
Por qué conviene. Las acciones sueltas de esta especificación (ia, ivr, desviar, buzon…) son menos de lo que se puede montar en el panel: con un escenario la llamada hace exactamente lo configurado, sin describirlo campo a campo en cada respuesta. Su servidor decide quién llama; el panel decide qué se hace con él.
En cualquier respuesta puede incluir el objeto contacto con los datos del llamante según su CRM. Este es el ejemplo completo —quién llama y qué hacemos con él— y es la forma recomendada de integrarse:
{
"escenario": "soporte-vip",
"contacto": {
"nombre": "Ana Perez",
"empresa": "Talleres Prieto",
"nota": "Cliente VIP - 12.480 EUR facturados - contrato hasta 03/2027",
"enlace": "https://sucrm.example/clientes/8812"
}
}
Qué ocurre con esos datos:
| campo | límite | dónde se ve |
| `nombre` | 40 | Identifica al llamante en el teléfono del agente (softphone, navegador y app), con prioridad sobre los contactos guardados en el panel: su CRM sabe más. |
| `empresa` | 60 | En la ficha de la llamada, dentro de la app. |
| `nota` | 200 | Texto libre: cualquier dato suyo — cliente VIP, total facturado, último pedido, incidencia abierta… Es lo que lee el agente antes de descolgar. |
| `enlace` | 300 | Enlace a la ficha en su sistema, desde la propia pantalla de llamada. Solo `https://`: cualquier otro esquema se descarta. |
| `apellidos` | 80 | Solo en `consulta_contacto`: rellena los apellidos del contacto que se está creando. |
| `email` | 120 | Solo en `consulta_contacto`: rellena el correo del contacto. Tiene que ser una dirección válida. |
| `idcliente` | 64 | Solo en `consulta_contacto`: el identificador de esa persona en su sistema. Se guarda con el contacto y, a partir de ahí, se lo enviamos en cada `llamada_entrante` de ese teléfono. |
La ficha se guarda con la llamada, no solo mientras suena: la app de teléfono la muestra en la pantalla de llamada y en el historial sin volver a consultar su servidor —no le pedimos nada con el timbre sonando, ni una vez por cada aparato—, y desde ese historial el agente puede dar de alta el contacto en la agenda de la cuenta con un toque. A partir de ahí, ese número ya sale identificado en las siguientes llamadas aunque su servidor no conteste.
Los campos que no están en la tabla se ignoran, y los textos se recortan al límite indicado: al otro lado hay un móvil sonando y una nota de dos mil caracteres no cabe en esa pantalla.
PETICIÓN POST (JSON) QUE ENVIAMOS A SU URL AL RECIBIRSE UNA LLAMADA.
La petición va firmada con la cabecera X-Mensatek-Signature: sha256=HMAC_SHA256(cuerpo, clave) (verifíquela, ver Introducción). Su servidor debe responder en el tiempo configurado (2-8 s) con código 2xx y un JSON con la acción a ejecutar (ver «La respuesta de su servidor» en la Introducción). Si no, se aplica la acción por defecto de su panel y la llamada continúa sin su intervención.
Parámetros recibidos en su script en petición POST con la configuración especificada en su panel de usuario/configuración API.
| evento required | string Momento de la llamada en que le consultamos: |
| from required | string Número del LLAMANTE en formato internacional +E164. Úselo para identificar al cliente en su sistema. |
| to required | string Su número de voz LLAMADO, en formato internacional +E164. |
| numero required | string Su número de voz llamado SIN el signo +. Útil si tiene varios números apuntando a la misma URL. |
| call_id required | string Identificador único de la llamada. Guárdelo si quiere correlacionar posteriores eventos de la misma llamada. |
| direccion required | string Sentido de la llamada. Actualmente siempre |
| hora required | string Fecha y hora de la llamada en UTC, formato ISO-8601. |
{- "evento": "llamada_entrante",
- "from": "+34600000001",
- "to": "+34910000001",
- "numero": "34910000001",
- "call_id": "v3:Gvpt8EiClUDCgsxRoMGUI4YsXq1nQ-pdKZRgdSdjQrOy8LQenTuq3A",
- "direccion": "entrante",
- "hora": "2026-07-24T10:15:30Z"
}