WebSocket API
ProductFlo implements a robust WebSocket system that supports both native WebSocket and Socket.IO protocols for real-time bidirectional communication. This unified interface powers various interactive features including chat, AI interactions, collaborative editing, and system notifications.
Connection Endpoints
Main WebSocket /ws
- Primary WebSocket endpoint (no authentication required)
Secure WebSocket /ws/secure
- Authenticated WebSocket endpoint requiring token
Socket.IO /ws
- Socket.IO compatible endpoint (conditionally mounted at runtime)
Message Structure
All WebSocket messages follow a consistent structure:
{
"code" : "chat" , // Required: Message type (from CodeType enum)
"user_id" : "user-123" , // Required: Sender user ID
"room_id" : "room-456" , // Optional: Target room for broadcasting
"timestamp" : "2024-05-19T10:30:45Z" , // Optional: ISO timestamp (auto-added if omitted)
"data" : { // Required: Message content
// Type-specific payload
}
}
Connection Examples
Standard WebSocket (Non-Authenticated)
// Connect to standard WebSocket endpoint
const socket = new WebSocket ( 'wss://api.productflo.io/ws' );
// Handle connection open
socket . onopen = () => {
console . log ( 'Connection established' );
};
// Listen for messages
socket . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
console . log ( 'Received:' , data );
};
// Send a message
function sendMessage ( message ) {
socket . send ( JSON . stringify ({
code: "chat" ,
user_id: "user-123" , // Use the user_id assigned by server or provided
room_id: "product-456" ,
data: {
message: message ,
sender: "user-123"
}
}));
}
Secure WebSocket (Authenticated)
// Connect to secure WebSocket endpoint with authentication
const socket = new WebSocket ( 'wss://api.productflo.io/ws/secure?access_token=YOUR_JWT_TOKEN' );
// Handle connection open
socket . onopen = () => {
console . log ( 'Authenticated connection established' );
};
// Listen for messages
socket . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
console . log ( 'Received:' , data );
};
// Send a message
function sendMessage ( message ) {
socket . send ( JSON . stringify ({
code: "chat" ,
user_id: "user-123" , // This should match the authenticated user ID
room_id: "product-456" ,
data: {
message: message ,
sender: "user-123"
}
}));
}
Socket.IO Client
import { io } from 'socket.io-client' ;
// Connect to Socket.IO endpoint
const socket = io ( 'https://api.productflo.io' , {
path: '/ws' ,
extraHeaders: { 'User-ID' : 'user-123' }, // Optional user ID
auth: { token: 'YOUR_JWT_TOKEN' }, // Optional token for authentication
reconnection: true
});
// Handle connection
socket . on ( 'connect' , () => {
console . log ( 'Connected to Socket.IO' );
});
// Listen for message events
socket . on ( 'message' , ( data ) => {
console . log ( 'Message received:' , data );
// Handle different message types
if ( data . data && data . data . code ) {
switch ( data . data . code ) {
case 'chat_response' :
handleChatResponse ( data . data );
break ;
case 'system' :
handleSystemMessage ( data . data );
break ;
// Handle other message types
}
}
});
// Send a message
function sendMessage ( message ) {
socket . emit ( 'message' , {
code: "chat" ,
user_id: "user-123" ,
room_id: "product-456" ,
data: {
message: message ,
sender: "user-123"
}
});
}
Authentication
WebSocket connections support multiple authentication methods:
Secure Endpoint
For authenticated connections, use the /ws/secure
endpoint which requires a token:
// Using query parameter
const socket = new WebSocket ( 'wss://api.productflo.io/ws/secure?access_token=YOUR_JWT_TOKEN' );
// OR using cookies (if token was set in cookies during login)
const socket = new WebSocket ( 'wss://api.productflo.io/ws/secure' );
Non-Authenticated Connection
For connections that don’t require authentication, use the standard /ws
endpoint:
const socket = new WebSocket ( 'wss://api.productflo.io/ws' );
The system will assign a unique user ID if none is provided.
Socket.IO Authentication
When using Socket.IO, provide authentication information in headers or cookies:
const socket = io ( 'https://api.productflo.io' , {
path: '/ws' ,
extraHeaders: { 'User-ID' : 'user-123' }, // Optional user ID
auth: { token: 'YOUR_JWT_TOKEN' } // Optional token
});
Message Types (CodeType)
The WebSocket system uses a set of predefined message types through the CodeType
enum:
Sending Types (Client to Server)
AI assistant chat interaction
Document generation request
Engineering-specific requests
Receiving Types (Server to Client)
Response to chat messages
Product idea generation response
Document generation response
Engineering-specific responses
System notifications and status updates
Status Types
All responses include a status field:
Operation completed successfully
Error occurred during operation
Operation is still in progress
Basic Usage Examples
Chat Message
// Send a chat message
socket . send ( JSON . stringify ({
code: "chat" ,
user_id: "user-123" ,
room_id: "product-456" ,
data: {
message: "Has anyone reviewed the latest design update?" ,
sender: "user-123"
}
}));
AI Assistant Interaction
// Send a message to the AI assistant
socket . send ( JSON . stringify ({
code: "haitch_chat" ,
user_id: "user-123" ,
room_id: "product-456" ,
data: {
message: "What materials would be best for a waterproof enclosure?" ,
sender: "user-123"
}
}));
Document Generation Request
// Request document generation
socket . send ( JSON . stringify ({
code: "documentation" ,
user_id: "user-123" ,
room_id: "product-456" ,
data: {
message: "Generate a technical specification document for our thermostat" ,
sender: "user-123" ,
attached_files: [ "requirements.pdf" ]
}
}));
Event Handling Example
// Set up event handling for different message types
socket . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
switch ( data . code ) {
case "chat_response" :
displayChatMessage ( data );
break ;
case "idea_response" :
showIdeaResults ( data );
break ;
case "documentation_response" :
handleDocumentGeneration ( data );
break ;
case "engineering_response" :
processEngineeringResponse ( data );
break ;
case "system" :
handleSystemMessage ( data );
break ;
case "notification" :
showNotification ( data );
break ;
case "error" :
handleError ( data );
break ;
default :
console . log ( "Unhandled message type:" , data );
}
};
Error Handling
Error responses follow a standardized format:
{
"status" : "error" ,
"code" : "system" ,
"user_id" : "user-123" ,
"timestamp" : "2024-05-19T10:30:45Z" ,
"data" : {
"message" : "Error message here" ,
"details" : {
"error_code" : "SPECIFIC_ERROR_CODE" ,
"message" : "Detailed error message"
}
}
}
Common error codes:
MESSAGE_CODE_REQUIRED
: Missing message code
UNSUPPORTED_MESSAGE_TYPE
: Unknown message type
ROOM_ID_REQUIRED
: Room ID not provided
FAILED_TO_PROCESS_MESSAGE
: General processing error
Connection Lifecycle
The WebSocket connection follows a distinct lifecycle:
Connection : Client establishes connection with optional authentication
Welcome : Server sends a system message confirming connection
Cookie : Server sets a user ID cookie if not present
Interaction : Exchange of messages based on application needs
Disconnection : Triggered by client disconnect or timeout
When a client connects, they’ll receive a welcome message:
{
"status" : "success" ,
"code" : "system" ,
"user_id" : "user-123" ,
"timestamp" : "2024-05-19T10:30:45Z" ,
"data" : {
"message" : "Connected to ProductFlo WebSocket server" ,
"details" : {
"user_id" : "user-123" ,
"timestamp" : "2024-05-19T10:30:45Z"
}
}
}
Implementation Details
The WebSocket system is built on three key components:
WebSocketManager (utils/websocket_manager.py
): Central component for connection management, message routing, and broadcasting
Message Types (models/websocket.py
): Pydantic models for typed message validation
Route Handlers (api/routes/websocket.py
): FastAPI WebSocket endpoint definitions
The implementation supports both direct point-to-point messages and room-based broadcasting patterns.
Best Practices
When implementing client applications:
Reconnection Logic : Implement automatic reconnection with exponential backoff
Message Validation : Validate outgoing messages against the API schema
Error Handling : Process error responses and retry when appropriate
Event Delegation : Use an event-based architecture to handle different message types
Typing Indicators : Send typing indicators for improved user experience
Next Steps