Skip to main content

Overview

VIZOCHOK uses a WebSocket-based protocol for real-time streaming chat. The protocol is designed around three principles:
  1. Auth via first message — credentials are sent as the first WebSocket message, not as query parameters (which would appear in server logs).
  2. Structured messages — all messages are JSON objects with a type field for routing.
  3. Streaming text — LLM responses are delivered token-by-token via text_delta messages for real-time display.

Connection Lifecycle

1

WebSocket Connect

Client establishes WebSocket connection. Server accepts.
2

Authentication

Client sends {"type":"auth","token":"pk_..."} (must be first message). Server responds with {"type":"auth_ok"}.
3

Session Initialization

New conversation: Server sends {"type":"conversation_started", "conversation_id":"..."}Reconnection: Server sends {"type":"session_restored", "conversation_id":"...", "selected_items":[...]} with cart state and pending tools.
4

Message Exchange

Client sends {"type":"message","text":"..."}. Server responds with status updates, text_delta chunks (repeated), text_end, and response_complete.
5

Disconnect

Client closes connection or disconnects. Session is saved to Redis for reconnection.

Endpoint

For self-hosted deployments, replace the host with your API base URL. The SDK automatically converts https:// to wss://.

Client to Server Messages

auth

Must be the first message sent after connection. The server waits up to 10 seconds for this message before closing the connection with code 4001.

message

Send a text message from the user.

action

Send a user action in response to an interactive tool (product selection, quick reply, checklist, meal plan).

ping

Client-initiated keepalive message. The SDK sends this every 30 seconds.

pong

Response to a server-initiated ping. Must be sent within 60 seconds to avoid heartbeat timeout.

Server to Client Messages

auth_ok

Confirms successful authentication. Sent immediately after a valid auth message.

conversation_started

Sent when a new conversation is created (first message with no conversation_id).

session_restored

Sent on reconnect when the client provides an existing conversation_id that has an active Redis session. Contains the current cart state and any pending interactive tool. The pending_tool object varies by tool type:

text_delta

A single token (or small chunk) of streaming text from the LLM. Multiple text_delta messages form a complete text block, terminated by text_end.

text_end

Signals the end of a streaming text block. After this, the streaming cursor should stop.

text

A complete text block (non-streaming). Used for short, pre-formed responses.

status

Progress indicator during tool execution. Replaced in the UI when a new status arrives for the same message. Status codes:

product_cards

Display a set of products for the user to select from.

quick_replies

Display quick reply buttons for the user to choose from.

confirmation

Confirms a cart operation (add, remove, update).

ingredient_checklist

Display a recipe ingredient checklist for user selection. Each IngredientItem:

meal_plan

Display a generated meal plan for the user to approve or modify.

session_summary

Display a summary of the current session’s cart.

cart_changed

Notification that the cart was modified. This is a UI-only event — the actual cart state lives on the client’s backend.

response_complete

Signals the end of an agent response. The conversation is ready for the next user message.

error

An error occurred while processing the message.

event

Internal server events. Currently ignored by the SDK but can be used for analytics.

ping / pong

Server-initiated heartbeat. The client must respond with {"type": "pong"} within 60 seconds.
Server response to a client-initiated ping:

Close Codes

Reconnection Strategy

The SDK implements automatic reconnection with exponential backoff and jitter:

Reconnection Rules

  • Reconnects on: Network errors, unexpected disconnects, heartbeat timeouts
  • Does not reconnect on: Auth errors (4001, 4002, 4003, 4004), clean close, explicit disconnect() call
  • Attempt counter resets: On successful connection (before auth)
  • Network awareness: Listens for browser online/offline events; reconnects when the network comes back

Session Restore on Reconnect

When the client reconnects with a conversation_id:
  1. Server loads the session from Redis (if still within the 1-hour TTL)
  2. Server sends a session_restored message with cart state and any pending tool
  3. Client can continue the conversation seamlessly
If the Redis session has expired, the server creates a new conversation.

Heartbeat

Both client and server send periodic heartbeat messages to detect dead connections: The server closes the connection with code 4008 if no pong is received within 60 seconds.

Message Size Limits

The SDK checks message size before sending and returns a message_too_large error via onError without transmitting the message. The server also enforces the 64 KB limit and responds with an error if exceeded.

Origin Validation

The server checks the Origin header of the WebSocket connection against the configured allowed origins list:
  • If the origin is not in the allowed list, the connection is closed with code 4003
  • This prevents unauthorized websites from connecting to the WebSocket API
  • The origin list is configured via the CORS_ORIGINS environment variable
Due to a Starlette/FastAPI limitation, the WebSocket must be accepted before the origin can be checked. The connection is accepted first, then immediately closed with a custom code if the origin is not allowed.