Upgrade /ws/:instance, protocol, authentication, Origin validation, heartbeat, and reconnection
GET
/
ws
/
:instance
Connect via 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" }}
HTTP → WebSocket upgrade endpoint to receive events in real time. Frames sent by the server use the same envelope as webhooks: a JSON text with event, data, and instanceData.Configuration (enable, filter events, toggle mediaBase64) is done at POST /api/events/websocket/:instance. This page covers only the connection layer.
Prerequisite: the instance must have WebSocket configured with enabled=true. Without that, the upgrade fails with 400 before becoming a WS connection.
Performs the raw HTTP→WebSocket upgrade handshake just to inspect status, headers, and confirm that the instance is accepting connections. It does not keep the channel open, it’s a one-shot probe.
Opens a real interactive WebSocket session with wscat (or an equivalent client in each language) and prints every received JSON frame. The most practical way to debug events in real time during development.
# npm i -g wscatwscat -c "wss://api.example.com/ws/$Instance_Name?token=$Token_Instance"
instanceData.token is the instance’s own token, useful when a client consumes multiple instances and needs to identify the source or make REST calls back.
When ENCRYPTION_KEY is configured, the token comes decrypted in the payload. Filter/redact it in client logs if you log the entire frame.
The query param is practically required for browser clients, since the browser’s new WebSocket(url) API doesn’t allow custom headers.Server-side clients (Node, Go, Python, etc.) should prefer the token header, query params leak into proxy/CDN logs.
Clients without an Origin header (curl, Postman, Node/Python/Go libs) are always accepted, Origin is a browser mechanism, not universal. Security for those clients comes from the token.Blocks are logged as WebSocket upgrade blocked from origin <origin> (host <host>). The client receives 403 Forbidden (no body) and the TCP is closed.
No PONG within 60s → the server drops the connection. There is no session resume: the client must reconnect with backoff and events lost during the gap do not return.Most WebSocket libraries (gorilla/websocket, Node ws, Python websockets, native browser) reply PONG automatically, the client almost never needs to implement this manually.
The 6 possible types (message.exchange, message.status, call.update, group.flow, instance.state, label.update) share this envelope. Full schemas and examples at /en/api/events/catalog.
In-memory hub: the handler registers the client in WebSocketHub (map[instanceName]map[*WebSocketClient]bool). The connection is not persisted. A process restart drops them all.
Goroutines: each connection spawns 2 goroutines (WritePump and ReadPump) that live until close.
No DB write: the upgrade itself writes nothing. Subsequent broadcasts go through the webhook dispatcher (which touches the DB) in parallel, WS is just an additional fanout.
No retry/persistence: a client offline for 5 min loses 5 min of events. For guarantees, use webhook.
Multi-client: multiple clients can connect to the same instance. All of them receive all events (broadcast). There is no atomicity for “who processed first”.
Filters are global per instance: the events[] filter configured at POST /api/events/websocket/:instance applies to all clients, it’s not configurable per connection.
Server frame size: the 4096-byte limit applies only to messages sent by the client. The server sends potentially much larger frames (base64 media easily exceeds 100KB). Read frames without limits in the client.
All occur before 101 Switching Protocols, the client receives a normal HTTP response.
HTTP
error.message
When
400
WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/<instance>
No config or enabled=false.
401
Missing token in header, Authorization header, or query parameter
None of the 3 sources provided a token.
401
Invalid token
Invalid token.
403
— (empty body, from the upgrader)
Origin outside the allowlist.
404
Instance not found
:instance does not exist.
429
Rate limit exceeded. Try again later.
Global rate-limit.
500
Failed to get instance / Failed to get websocket configuration
Database error.
{ "success": false, "error": { "message": "WebSocket is not enabled for this instance. Configure it first using POST /api/events/websocket/$Instance_Name" }}
After 101, any protocol failure closes the connection with a standard close code (1001 going away, 1006 abnormal closure, 1011 server error). The server doesn’t write a body, the client handles it via the close code.Common causes:
Client frame larger than 4096 bytes.
pongWait (60s) expired without a reply to the PING.
Client send buffer full (slow client), the hub unregisters it.
Instance was deleted while the client was connected.