Skip to main content
GET
Conectar vía WebSocket
Auth: TokenAccount o TokenInstance (header o query) • Protocolo: WSS/WS • Rate-limit: Global (100/min en el upgrade)

Descripción

Endpoint de upgrade HTTP → WebSocket para recibir eventos en tiempo real. Los frames enviados por el servidor usan el mismo envoltorio que los webhooks: un JSON de texto con event, data e instanceData. La configuración (habilitar, filtrar eventos, alternar mediaBase64) se hace en POST /api/events/websocket/:instance. Esta página cubre solo la capa de conexión.
Prerrequisito: la instancia debe tener WebSocket configurado con enabled=true. Sin eso, el upgrade falla con 400 antes de convertirse en una conexión WS.

Ejemplos cURL (handshake)

websocat o wscat te dan una experiencia interactiva. cURL solo es útil para inspeccionar el handshake.

Handshake (inspección)

Realiza el handshake bruto de upgrade HTTP→WebSocket solo para inspeccionar status, cabeceras y confirmar que la instancia está aceptando conexiones. No mantiene el canal abierto: es una sonda one-shot.

wscat (interactivo)

Abre una sesión WebSocket interactiva real con wscat (o un cliente equivalente en cada lenguaje) e imprime cada frame JSON recibido. La forma más práctica de depurar eventos en tiempo real durante el desarrollo.

Ejemplos de cliente

Los navegadores no permiten cabeceras personalizadas en WebSocket, usa ?token=:

Envoltorio de los frames recibidos

Cada frame de texto es un JSON idéntico al webhook:
instanceData.token es el token propio de la instancia, útil cuando un cliente consume varias instancias y necesita identificar el origen o realizar llamadas REST de regreso.
Cuando ENCRYPTION_KEY está configurado, el token viene descifrado en el payload. Filtra/redacta este valor en los logs del cliente si registras el frame completo.

Parámetros de ruta

string
requerido
Nombre de la instancia. Debe existir y tener WebSocket habilitado.

Cabeceras

Parámetros de consulta

string
Token de autenticación. Requerido cuando el cliente no puede enviar token o Authorization en la cabecera (caso del navegador).

Precondiciones

  1. Existe una configuración en websocket_configs para la instancia (creada vía POST /api/events/websocket/:instance) con enabled=true.
  2. Token válido, TokenAccount o TokenInstance de la instancia (misma matriz que REST).
  3. Si proviene de un navegador, el Origin del request está en ALLOWED_WS_ORIGINS o es same-origin.
La validación ocurre antes del upgrade HTTP→WS. Después del upgrade no hay re-autenticación: la sesión TCP es confiable hasta que se cierra.

Autenticación

ValidateTokenFlexible() acepta el token desde tres fuentes:
El query param es prácticamente requerido para clientes en navegador, ya que la API new WebSocket(url) del navegador no permite cabeceras personalizadas.Los clientes del lado servidor (Node, Go, Python, etc.) deben preferir la cabecera token, los query params se filtran a logs de proxy/CDN.

Validación de Origin (ALLOWED_WS_ORIGINS)

Independiente del CORS (que solo afecta al REST), el WebSocket tiene su propia allowlist controlada por la variable de entorno ALLOWED_WS_ORIGINS.
Los clientes sin la cabecera Origin (curl, Postman, libs de Node/Python/Go) siempre son aceptados, Origin es un mecanismo del navegador, no universal. La seguridad para esos clientes proviene del token.Los bloqueos se registran como WebSocket upgrade blocked from origin <origin> (host <host>). El cliente recibe 403 Forbidden (sin body) y se cierra el TCP.

Heartbeat

Sin PONG en 60s → el servidor cierra la conexión. No hay session resume: el cliente debe reconectar con backoff y los eventos perdidos durante el gap no regresan. La mayoría de las librerías WebSocket (gorilla/websocket, Node ws, Python websockets, navegador nativo) responden PONG automáticamente, el cliente casi nunca necesita implementar esto manualmente.

Buffers y backpressure

El servidor no consume mensajes enviados por el cliente (solo PONG y close). Enviar payloads JSON desde el cliente al servidor no tiene efecto.

Catálogo de eventos

Los 6 tipos posibles (message.exchange, message.status, call.update, group.flow, instance.state, label.update) comparten este envoltorio. Esquemas y ejemplos completos en /es/api/events/catalog.

Reconexión y resiliencia

El servidor no replays los eventos perdidos durante outages, el cliente WS es fire-and-forget. Para garantía de entrega, usa webhook en paralelo.
Siempre ten un handler de close con reconexión automática, idealmente con backoff exponencial y jitter, limitado a 30s entre intentos.
Maneja los close codes: 1006 (network drop), 1011 (server error), 1008 (policy violation), 4xxx (custom, raros).
Catch up vía REST después de reconectar, usa GET /api/chat/history/:instance para traer mensajes recientes que pudieron perderse.
Buffer local en el cliente, nunca bloquees el handler de message con operaciones lentas; encola y procesa en otro thread/worker.

Efectos colaterales

  • Hub en memoria: el handler registra al cliente en WebSocketHub (map[instanceName]map[*WebSocketClient]bool). La conexión no se persiste. Un restart del proceso los descarta a todos.
  • Goroutines: cada conexión genera 2 goroutines (WritePump y ReadPump) que viven hasta el close.
  • Sin escritura en BD: el upgrade en sí no escribe nada. Los broadcasts subsiguientes pasan por el dispatcher de webhook (que toca la BD) en paralelo, el WS es solo un fanout adicional.
  • Métricas Prometheus: contadores de conexiones activas por instancia (consulta /es/api/observability/overview).

Notas

  • Sin retry/persistencia: un cliente offline por 5 min pierde 5 min de eventos. Para garantías, usa webhook.
  • Multi-cliente: varios clientes pueden conectarse a la misma instancia. Todos reciben todos los eventos (broadcast). No hay atomicidad para “quién procesó primero”.
  • Filtros son globales por instancia: el filtro events[] configurado en POST /api/events/websocket/:instance se aplica a todos los clientes, no es configurable por conexión.
  • Tamaño de frame del servidor: el límite de 4096 bytes solo se aplica a mensajes enviados por el cliente. El servidor envía frames potencialmente mucho más grandes (media en base64 supera fácilmente 100KB). Lee frames sin límites en el cliente.

Cuándo usar webhook vs WebSocket

  • Webhook: integraciones server-to-server donde la pérdida es inaceptable (CRM, ERP, analytics, log sink).
  • WebSocket: UIs en tiempo real (dashboard, live inbox, pantalla de soporte) donde la baja latencia es prioridad y pérdidas ocasionales son aceptables.
  • Ambos en paralelo: webhook persiste el estado, WS hace que la UI vibre.

Errores antes del upgrade

Todos ocurren antes de 101 Switching Protocols, el cliente recibe una respuesta HTTP normal.

Errores después del upgrade

Después de 101, cualquier falla de protocolo cierra la conexión con un close code estándar (1001 going away, 1006 abnormal closure, 1011 server error). El servidor no escribe un body, el cliente lo maneja vía el close code. Causas comunes:
  • Frame del cliente mayor a 4096 bytes.
  • pongWait (60s) expiró sin respuesta al PING.
  • Send buffer del cliente lleno (cliente lento), el hub lo desregistra.
  • La instancia fue eliminada mientras el cliente estaba conectado.

Referencias

Configurar WebSocket

POST /api/events/websocket/:instance

Catálogo de eventos

Esquemas de los 6 tipos.

Resumen de eventos

Webhook vs WebSocket, envoltorio, mejores prácticas.

Autenticación

Matriz de tokens, header token, ?token=.