16. Eventos em Tempo Real (SSE/WebSocket)#
Receba eventos em tempo real sem polling. Ideal para dashboards e chatbots.
GET/v1/instances/{instanceId}/events (SSE)#
Server-Sent Events stream.
Auth: Header Authorization: Bearer <jwt> ou X-API-Key: <key>
Empresa ativa (mesma regra da seção 1 - Autenticação): com JWT, a cada conexão o servidor consulta o master DB: empresa inexistente → 403 (company not found), suspensa → 403 (company suspended), falha de banco nessa consulta → 503 (service unavailable). Com API key, empresa suspensa → 403; token inválido → 401.
Query Parameters:
| Parametro | Tipo | Descricao |
|---|---|---|
events |
string | Filtro de eventos (separados por virgula). Ex: message.received,connection.update |
last_event_id |
string | Cursor opcional para replay curto. Se informado, o servidor reenviara eventos buffered posteriores a esse ID |
Resume/Replays: o SSE também aceita o header Last-Event-ID. O hub mantem um buffer em memória com os 100 eventos mais recentes por instância para retomada após desconexoes curtas.
Limite por instância: máximo de 20 conexões SSE/WebSocket simultaneas por instância. Excesso retorna 429 Too Many Requests.
Formato dos eventos:
event: connected
data: {"instance_id": "84c2e480-..."}
event: message.received
id: evt_1234
data: {"event_id":"550e8400-...","type":"message.received","instance_id":"84c2e480-...","timestamp":"2026-03-07T15:30:45.123Z","data":{...}}
: heartbeat
Evento live-only do Audit Timeline: quando o worker grava uma linha em stealth_audit_events, ele pública um evento SSE/WS stealth.audit_event no mesmo canal Redis por instância. Esse evento existe para refresh imediato da UI e não entra em webhooks nem em GET /events/history.
Payload stealth.audit_event:
{
"id": 42,
"instance_id": "84c2e480-...",
"event_type": "connection.opened",
"event_data": {
"proxy_city": "sao-paulo",
"spec": "hello_chrome_120"
},
"occurred_at": "2026-04-20T22:30:00Z",
"created_at": "2026-04-20T22:30:00Z"
}
Vocabulario controlado de event_type (v1):
fingerprint.assignedfingerprint.rotatedwarmup.phase_changedwarmup.bypass_grantedwarmup.bypass_expiredconnection.openedconnection.closedconnection.bannedhygiene.appliedhumanize.appliedstealth.inbound_first.blockedstealth.app_version_canary_startedstealth.app_version_fleet_appliedstealth_transport.debug_enabledstealth_transport.debug_renewedstealth_transport.debug_expired
Notas warmup:
warmup.phase_changede gravado de forma transacional junto com oUPDATE tenant_instances.warmup_phase.warmup.bypass_grantede emitido porPOST /v1/admin/instances/{instanceId}/warmup/bypasse carregareason,ticket_id,tokeneexpires_atdentro deevent_data.hygiene.appliede emitido uma vez por alteração bem-sucedida (push_name,photo,status) e carregatype+valuedentro deevent_data.
Exemplo com curl:
curl -N \
-H "Authorization: Bearer eyJ..." \
"https://api.catcher.one/v1/instances/84c2e480/events?events=message.received,connection.update"
Exemplo com JavaScript (fetch streaming):
const response = await fetch(
'https://api.catcher.one/v1/instances/84c2e480/events?events=message.received',
{
headers: { Authorization: `Bearer ${token}` }
}
);
// Leia response.body como ReadableStream e parseie o protocolo SSE.
GET/v1/instances/{instanceId}/events/history#
Histórico de eventos persistidos com paginação baseada em cursor.
Auth: Bearer JWT ou API Key
Query Parameters:
| Parametro | Tipo | Descricao |
|---|---|---|
limit |
int | Máximo de eventos (1-200, padrão 50) |
before |
string | Cursor: event_id para buscar eventos anteriores (DESC) |
after |
string | Cursor: event_id para buscar eventos posteriores (ASC, catch-up) |
since |
string | Timestamp RFC3339 para buscar eventos a partir de (ASC) |
types |
string | Filtro por tipo(s) de evento, separados por virgula. Ex: message.received,message.sent |
contains |
string | Busca por substring em qualquer campo principal do evento: event_id, type, instance_id, timestamp e no JSON data (chaves e valores). Ex: contains=ABC123 encontra todos eventos que referenciam o WhatsApp message ID ABC123; contains=message.sent filtra por tipo; contains=2026-04-23 encontra eventos daquela data |
Resposta 200:
{
"events": [
{
"event_id": "ca5e3b45-055a-4ccc-be37-cb9d76d25887",
"type": "message.received",
"instance_id": "be23db3e-900d-4194-98ca-7a1deb2157a5",
"timestamp": "2026-04-04T17:34:55.965Z",
"data": {
"message_ids": ["ABC123"],
"chat": "5511999999999@s.whatsapp.net",
"from": "5511999999999@s.whatsapp.net",
"type": "text",
"content": "Ola!"
}
}
],
"has_more": true
}
Correlação de eventos com mensagens: Use contains com o whatsapp_id da mensagem para encontrar todos os eventos relacionados (received, sent, delivered, read, deleted, edited).
Busca paginada: quando contains estiver presente, a paginação (before / after) continua sendo aplicada sobre o conjunto filtrado. Exemplo: limit=50&contains=oi retorna os 50 eventos mais recentes que contenham oi; o próximo before=<ultimo_event_id> retorna os 50 matches seguintes, não apenas os próximos 50 eventos brutos.
GET/v1/instances/{instanceId}/events/stats#
Estatísticas agregadas dos eventos de uma instância.
Auth: Bearer JWT ou API Key
Resposta 200:
{
"total_count": 1523,
"count_by_type": {
"message.received": 450,
"message.sent": 320,
"message.delivered": 310,
"message.read": 280
},
"latest_timestamp": "2026-04-04T17:34:55.965Z"
}
GET/v1/instances/{instanceId}/ws (WebSocket)#
Conexão WebSocket para eventos em tempo real.
Auth: Header Authorization ou X-API-Key (mesma regra do SSE).
Query Parameters: events e last_event_id. A autenticação não aceita mais token em query string.
Comportamento:
- Upgrade para WebSocket (101 Switching Protocols)
- Somente leitura (servidor envia, cliente recebe)
- Ping a cada 30s para manter a conexão
- Mensagens em formato JSON
- Replay inicial opcional a partir de
last_event_id - Se o limite de 20 subscribers por instância for excedido, a API responde
429antes do upgrade
Exemplo com Node.js (ws com headers):
const WebSocket = require('ws');
const ws = new WebSocket(
'wss://api.catcher.one/v1/instances/84c2e480/ws?events=message.received',
{
headers: { Authorization: `Bearer ${token}` }
}
);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Evento:', data.type, data);
};