Upgrade /ws/:instance, protocolo, autenticación, validación de Origin, heartbeat y reconexión
GET
/
ws
/
:instance
Conectar vía WebSocket
curl --request GET \ --url https://api.example.com/ws/:instance
{ "success": false, "error": { "message": "WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/$Instance_Name" }}
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.
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.
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.
# npm i -g wscatwscat -c "wss://api.example.com/ws/$Instance_Name?token=$Token_Instance"
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.
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.
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.
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.
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.
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.
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.
Todos ocurren antes de 101 Switching Protocols, el cliente recibe una respuesta HTTP normal.
HTTP
error.message
Cuándo
400
WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/<instance>
Sin config o enabled=false.
401
Missing token in header, Authorization header, or query parameter
Ninguna de las 3 fuentes proporcionó un token.
401
Invalid token
Token inválido.
403
— (body vacío, desde el upgrader)
Origin fuera de la allowlist.
404
Instance not found
:instance no existe.
429
Rate limit exceeded. Try again later.
Rate-limit global.
500
Failed to get instance / Failed to get websocket configuration
Error de base de datos.
{ "success": false, "error": { "message": "WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/$Instance_Name" }}
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.