Eventos
Conectar via WebSocket
Upgrade /ws/:instance, protocolo, autenticação, validação de Origin, heartbeat e reconexão
GET
Conectar via WebSocket
Auth:
Validação de Origin (
Independente do CORS (que afeta só REST), o WebSocket tem sua própria allowlist controlada pela env var
Sem PONG em 60s → o servidor dropa a conexão. Não há resumo de sessão: o cliente deve reconectar com backoff e os eventos perdidos no intervalo não voltam.
A maioria das libs WebSocket (
O servidor não consome mensagens enviadas pelo cliente (apenas PONG e fechamento). Enviar payloads JSON do cliente para o servidor não tem efeito.
TokenAccount ou TokenInstance (header ou query) • Protocolo: WSS/WS • Rate-limit: Global (100/min sobre o upgrade)
Descrição
Endpoint de upgrade HTTP → WebSocket para receber eventos em tempo real. Os frames enviados pelo servidor têm o mesmo envelope dos webhooks, texto JSON comevent, data e instanceData.
A configuração (habilitar, filtrar eventos, ativar mediaBase64) é feita em POST /api/events/websocket/:instance. Esta página cobre apenas a camada de conexão.
Exemplos cURL (handshake)
websocat ou wscat dão experiência interativa. cURL serve só para inspecionar o handshake.
Handshake (inspeção)
Faz o handshake bruto de upgrade HTTP→WebSocket apenas para inspecionar status, headers e validar que a instância está aceitando conexões. Não mantém o canal aberto, é uma sondagem one-shot.wscat (interativo)
Abre uma sessão WebSocket interativa real comwscat (ou cliente equivalente em cada linguagem) e fica imprimindo cada frame JSON recebido. Forma mais prática para debugar eventos em tempo real durante o desenvolvimento.
Exemplos de cliente
- Browser (JS)
- Node.js (ws)
- Python (websockets)
- Go (gorilla)
Browsers não permitem customizar headers no
WebSocket, use ?token=:Envelope dos frames recebidos
Cada frame de texto é um JSON idêntico ao webhook:instanceData.token é o token da própria instância, útil quando o cliente consome múltiplas instâncias e precisa identificar a origem ou fazer chamadas REST de volta.
Parâmetros de rota
Nome da instância. Deve existir e ter WebSocket habilitado.
Headers
| Nome | Obrigatório | Exemplo | Descrição |
|---|---|---|---|
token ou Authorization | sim, salvo se usar ?token= | token: a1b2c3... | Auth flexível. |
Upgrade | sim | websocket | Exigido pelo protocolo. |
Connection | sim | Upgrade | Idem. |
Sec-WebSocket-Key | sim | (gerado pelo cliente) | Idem. |
Sec-WebSocket-Version | sim | 13 | Único valor aceito. |
Origin | condicional | https://app.exemplo.com | Validado contra allowlist em browsers. Clients sem Origin são aceitos. |
Query parameters
Token de autenticação. Obrigatório quando o cliente não pode enviar
token ou Authorization no header (caso dos browsers).Pré-condições
- Existe uma config em
websocket_configspara a instância (criada viaPOST /api/events/websocket/:instance) comenabled=true. - Token válido,
TokenAccountouTokenInstanceda instância (mesma matriz do REST). - Se vier de browser, o
Origindo request está emALLOWED_WS_ORIGINSou é same-origin.
Autenticação
ValidateTokenFlexible() aceita o token em três fontes:
| Fonte | Exemplo |
|---|---|
Header token | token: a1b2c3d4-... |
Header Authorization: Bearer | Authorization: Bearer a1b2c3d4-... |
Query param ?token= | wss://api.example.com/ws/minha?token=a1b2c3d4-... |
Validação de Origin (ALLOWED_WS_ORIGINS)
Independente do CORS (que afeta só REST), o WebSocket tem sua própria allowlist controlada pela env var ALLOWED_WS_ORIGINS.
ALLOWED_WS_ORIGINS | Comportamento |
|---|---|
| Vazio / não definido | Apenas same-origin (Origin igual ao Host) é aceito. |
"https://app.exemplo.com,https://dashboard.exemplo.com" | Allowlist explícita, separada por vírgula. |
Clientes sem header
Origin (curl, Postman, libs Node/Python/Go) são sempre aceitos, Origin é mecanismo do browser, não universal. A segurança para esses clientes é o token.Bloqueios são logados como WebSocket upgrade blocked from origin <origem> (host <host>). O cliente recebe 403 Forbidden (sem body) e a TCP é fechada.Heartbeat
| Lado | Mensagem | Intervalo |
|---|---|---|
| Servidor → cliente | PING | a cada ~54s (pingPeriod) |
| Cliente → servidor | PONG | dentro de 60s (pongWait) |
gorilla/websocket, ws do Node, websockets do Python, browser nativo) responde PONG automaticamente, o cliente quase nunca precisa implementar isso manualmente.
Buffers e backpressure
| Limite | Valor | Efeito ao estourar |
|---|---|---|
| Read buffer (max client message) | 4096 bytes | Servidor fecha a conexão. |
| Send buffer por cliente | 256 mensagens | Cliente lento é dropado pelo hub. |
Catálogo de eventos
Os 6 tipos possíveis (message.exchange, message.status, call.update, group.flow, instance.state, label.update) compartilham este envelope. Schemas e exemplos completos em /api/events/catalog.
Reconexão e resiliência
O servidor não replica eventos perdidos durante quedas, o cliente WS é fire-and-forget. Para garantia de entrega, use webhook em paralelo.Sempre tenha handler de
close com reconexão automática, idealmente com backoff exponencial e jitter, limitado a 30s entre tentativas.Trate close codes:
1006 (queda de rede), 1011 (erro do servidor), 1008 (policy violation), 4xxx (custom, raros).Catch-up via REST depois de reconectar, use
GET /api/chat/history/:instance para puxar mensagens recentes que possam ter sido perdidas.Buffer local no cliente, nunca bloqueie o handler
message com operações lentas; jogue em fila e processe em outra thread/worker.Efeitos colaterais
- Hub em memória: o handler registra o cliente em
WebSocketHub(map[instanceName]map[*WebSocketClient]bool). A conexão não é persistida. Reinício do processo derruba todos. - Goroutines: cada conexão lança 2 goroutines (
WritePumpeReadPump) que vivem até o close. - Sem DB write: o upgrade em si não escreve nada. Broadcasts subsequentes passam pelo dispatcher de webhook (que toca DB) em paralelo, WS é apenas fanout adicional.
- Métricas Prometheus: contadores de conexões ativas por instância (ver /api/observability/overview).
Notas
- Sem retry/persistência: cliente offline 5min = perde 5min de eventos. Para garantia, use webhook.
- Multi-cliente: vários clientes podem conectar na mesma instância. Todos recebem todos os eventos (broadcast). Não há atomicidade de “quem processou primeiro”.
- Filtros são globais por instância: o filtro
events[]configurado emPOST /api/events/websocket/:instancevale para todos os clientes, não é configurável por conexão. - Frame size do servidor: o limite de 4096 bytes vale apenas para mensagens enviadas pelo cliente. O servidor envia frames potencialmente bem maiores (mídia em base64 passa de 100KB facilmente). Leia frames sem limite no cliente.
Quando usar webhook vs WebSocket
| Critério | WebSocket | Webhook |
|---|---|---|
| Latência | ms (push direto) | 100-500ms (HTTP + fila) |
| Persistência | Eventos perdidos se offline | Fila + retry 5x + DLQ |
| Multi-consumer | Vários clientes em broadcast | Até 3 webhooks habilitados (labels) |
| Auth | Token no upgrade | Header Authorization opcional |
| Setup | Cliente WS + config habilitada | Endpoint HTTP público + URL |
| Dev-friendliness | Excelente (wscat, DevTools) | Requer tunneling em dev |
Erros antes do upgrade
Todas ocorrem antes do101 Switching Protocols, o cliente recebe um HTTP normal.
| HTTP | error.message | Quando |
|---|---|---|
| 400 | WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/<instance> | Sem config ou enabled=false. |
| 401 | Missing token in header, Authorization header, or query parameter | Nenhuma das 3 fontes forneceu token. |
| 401 | Invalid token | Token inválido. |
| 403 | , (body vazio, do upgrader) | Origin fora da allowlist. |
| 404 | Instance not found | :instance inexistente. |
| 429 | Rate limit exceeded. Try again later. | Rate-limit global. |
| 500 | Failed to get instance / Failed to get websocket configuration | Erro de banco. |
Erros após o upgrade
Depois do101, qualquer falha de protocolo fecha a conexão com um close code padrão (1001 going away, 1006 abnormal closure, 1011 server error). O servidor não escreve body, o cliente trata pelo close code.
Causas comuns:
- Frame do cliente maior que 4096 bytes.
pongWait(60s) expirou sem resposta ao PING.- Buffer de envio do cliente cheio (cliente lento), hub faz unregister.
- Instância foi deletada enquanto o cliente estava conectado.
Referências
Configurar WebSocket
POST /api/events/websocket/:instanceCatálogo de eventos
Schemas dos 6 tipos.
Visao geral de Eventos
Webhook x WebSocket, envelope, boas práticas.
Autenticação
Matriz de tokens, header
token, ?token=.