2CXVoIPDevelopers
2CXVoIP · Documentación para desarrolladores

2CXVoIP Communications API — guía de integración para el CRM

Esta API te da: login de agentes, un token de sesión para el softphone embebido, un canal en tiempo real para llamadas/SMS/presencia, y envío de SMS. La sesión del usuario (quién está logueado, en qué pestaña, su historial de conversación por contacto) la maneja tu CRM — esta API solo provee la infraestructura de comunicaciones (línea telefónica, saldo, y los eventos de la llamada).

Base URL: https://webphone.2cxvoip.com

Todas las respuestas de error usan el formato: { "error": "mensaje" }

1. Autenticación

POST /auth/login

// body
{ "email": "agente@tuempresa.com", "password": "..." }
// 200
{
  "token": "<jwt, válido 7 días>",
  "user": {
    "id": "uuid", "email": "...", "name": "...", "role": "agent|supervisor|admin",
    "status": "active", "team": "Ventas", "line": "+19165551234"
  }
}

Guarda token y mándalo como Authorization: Bearer <token> en cada request subsecuente (incluyendo el mensaje de auth del WebSocket, ver §3).

Rate limit: 5 intentos por IP cada 15 minutos.

GET /auth/me

Header: Authorization: Bearer <token>. Devuelve el mismo shape que user arriba — úsalo para validar el token al cargar tu app.

2. Softphone embebido

GET /api/webphone/token

Header: Authorization: Bearer <token>.

// 200
{ "session_token": "...", "line": "+19165551234", "expires_in": 900 }

session_token es válido ~15 minutos — pide uno nuevo antes de que expire (por ejemplo cada 10 min mientras el agente esté activo). Si el agente todavía no tiene línea asignada, la API responde 503 { "error": "No phone line assigned yet..." }.

Widget del softphone

No instales ningún SDK de terceros. Carga el widget de 2CXVoIP directo desde el CDN:

<script src="https://cdn.2cxvoip.com/softphone.js"></script>

Esto expone window.TwoCXSoftphone:

TwoCXSoftphone.connect(session_token)        // del GET /api/webphone/token de arriba
TwoCXSoftphone.on('ready', () => {...})
TwoCXSoftphone.on('incoming', ({ from }) => {...})   // muestra tu popup de llamada entrante
TwoCXSoftphone.on('callStateChange', ({ state }) => {...})
TwoCXSoftphone.on('error', (err) => {...})

TwoCXSoftphone.dial('+19165551234')          // llamada saliente
TwoCXSoftphone.answer()
TwoCXSoftphone.reject()
TwoCXSoftphone.hangup()
TwoCXSoftphone.disconnect()

Nota honesta: el widget saca cualquier dependencia del carrier de tu propio código y package.json — es la exposición práctica que más importa. No garantiza que el tráfico de red del navegador sea 100% irreconocible ante alguien inspeccionando la pestaña Network a propósito; eso queda fuera de lo que un wrapper del lado del cliente puede controlar.

3. Canal en tiempo real — WS /ws/presence

Conecta un socket por agente logueado. Primer mensaje siempre debe ser auth:

→ { "type": "auth", "token": "<jwt de /auth/login>" }
← { "type": "auth_ok", "userId": "uuid" }
   // o { "type": "auth_error" } seguido de cierre del socket

Mensajes que puedes enviar

{ "type": "status", "status": "available" | "busy" | "in_call" | "offline" }
{ "type": "ping" }   // heartbeat, responde { "type": "pong" }

Eventos que el servidor te empuja

presence_update — snapshot completo cada vez que cualquier agente cambia de estado (útil para un wallboard):

{ "type": "presence_update", "agents": [
  { "id": "uuid", "name": "...", "email": "...", "role": "agent",
    "team": "Ventas", "line": "+1916...", "status": "available" }
] }

call_incoming — una llamada está entrando a la línea del agente. Es solo la señal para mostrar el popup de "llamada entrante" con datos del caller en tu UI — el softphone (widget del navegador, autenticado con session_token) es quien realmente contesta/timbra:

{ "type": "call_incoming", "from": "+1...", "to": "+1916...", "callControlId": "..." }

sms_inbound — mensaje SMS entrante ya guardado, para refrescar el hilo de conversación del contacto:

{ "type": "sms_inbound", "conversationId": "uuid", "from": "+1...", "to": "+1916...",
  "text": "...", "contactId": "uuid" }

Cada evento solo se entrega al socket del agente dueño de la línea — no hay broadcast entre agentes.

GET /api/presence

Snapshot inicial (mismo shape que presence_update.agents) para cuando tu app carga y todavía no tiene el WebSocket conectado.

4. SMS

POST /api/sms/send

// body
{ "contact_id": "uuid", "body": "texto del mensaje" }

Envía desde la línea asignada al agente autenticado. 404 si el contacto no existe, 503 si el agente no tiene línea.

GET /api/contacts/:id/thread

Historial completo (SMS + llamadas) de un contacto:

{
  "contact": { "id": "...", "phone_e164": "...", "name": "...", "email": "..." },
  "messages": [{ "id", "direction", "body", "sent_at", "agent_name" }],
  "calls": [{ "id", "direction", "status", "duration_seconds", "started_at", "ended_at", "agent_name" }]
}

Útil si tu CRM todavía no tiene su propio store de conversaciones y quiere apoyarse en este endpoint — no es obligatorio, es una conveniencia.

5. Lo que NO es parte de esta API

6. CORS

Tu dominio de frontend debe estar en el allowlist del servidor antes de poder llamar esta API desde el navegador. Escribí a support@2cxvoip.com con tu(s) dominio(s) y tu número de cliente para que los agreguemos.