Skip to main content
Use the WebSocket API directly when you cannot use the JS SDK, for example in backend services, mobile apps, or custom chat UIs.

When to Use Direct WebSocket

Use the SDK

  • Web storefronts (any framework)
  • Standard floating or inline widget
  • Want built-in UI, reconnection, session management

Use Direct WebSocket

  • Backend-to-backend chat (e.g. Telegram bot)
  • Mobile apps (React Native, Flutter, native)
  • Custom chat UI with full control
  • Testing and automation

Quick Start

1

Connect to WebSocket

wss://api.vizochok.com/api/v1/ws/chat
2

Authenticate (first message)

{
  "type": "auth",
  "token": "pk_your_public_key",
  "store_id": "your-store",
  "user_id": "user-123"
}
Wait for {"type": "auth_ok"} before sending messages.
3

Send a message

{
  "type": "message",
  "text": "Show me milk",
  "conversation_id": "conv_abc123"
}
Omit conversation_id to start a new conversation.
4

Handle streaming response

You will receive multiple messages:
  1. {"type": "status", "code": "searching", ...} (progress indicator)
  2. {"type": "text_delta", "delta": "Here "} (repeated, concatenate)
  3. {"type": "text_end"} (text block complete)
  4. {"type": "product_cards", "items": [...]} (product results)
  5. {"type": "response_complete", ...} (ready for next message)

Python Example

import asyncio
import json
import websockets

async def chat():
    async with websockets.connect("wss://api.vizochok.com/api/v1/ws/chat") as ws:
        # Authenticate
        await ws.send(json.dumps({
            "type": "auth",
            "token": "pk_your_key",
            "store_id": "your-store",
            "user_id": "user-123",
        }))

        auth_response = json.loads(await ws.recv())
        assert auth_response["type"] == "auth_ok"

        # Wait for conversation_started
        init = json.loads(await ws.recv())
        conversation_id = init.get("conversation_id")

        # Send a message
        await ws.send(json.dumps({
            "type": "message",
            "text": "What milk do you have?",
            "conversation_id": conversation_id,
        }))

        # Collect streaming response
        full_text = ""
        while True:
            msg = json.loads(await ws.recv())
            if msg["type"] == "text_delta":
                full_text += msg["delta"]
            elif msg["type"] == "response_complete":
                break

        print(full_text)

asyncio.run(chat())

Node.js Example

const WebSocket = require('ws');

const ws = new WebSocket('wss://api.vizochok.com/api/v1/ws/chat');

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'auth',
    token: 'pk_your_key',
    store_id: 'your-store',
    user_id: 'user-123',
  }));
});

let conversationId = null;
let fullText = '';

ws.on('message', (data) => {
  const msg = JSON.parse(data);

  switch (msg.type) {
    case 'auth_ok':
      break;
    case 'conversation_started':
      conversationId = msg.conversation_id;
      ws.send(JSON.stringify({
        type: 'message',
        text: 'What milk do you have?',
        conversation_id: conversationId,
      }));
      break;
    case 'text_delta':
      fullText += msg.delta;
      break;
    case 'response_complete':
      console.log(fullText);
      ws.close();
      break;
  }
});

Session Management

  • Save the conversation_id from conversation_started or session_restored
  • Pass it in subsequent message calls to continue the same conversation
  • Sessions expire after 1 hour of inactivity in Redis
  • On reconnect with a valid conversation_id, the server sends session_restored with cart state

Heartbeat

Send {"type": "ping"} every 30 seconds to keep the connection alive. The server also sends pings and expects a {"type": "pong"} response within 60 seconds.

Full Protocol Reference

For the complete list of message types, fields, close codes, and error handling, see WebSocket Protocol.