Skip to main content

WebSocket API

Moveo's WebSocket API enables real-time communication between your application and Moveo's services. This is the same WebSocket API that the Moveo Web Client uses internally. You can use this API to build your own custom integration.

With this API you can:

  • Create and manage conversation sessions
  • Send and receive messages in real-time
  • Handle session lifecycle events
  • Implement custom message handling logic

Socket.IO protocol​

Moveo uses the Socket.IO protocol v4 to establish WebSocket communication between the client and the Moveo channels service.

To initiate a WebSocket connection, send a GET request to:

wss://channels-ws.moveo.ai/v1/web/{INTEGRATION-ID}/ws?EIO=4&transport=websocket

Replace {INTEGRATION-ID} with the ID of the Web integration in Moveo. The server rejects a connection without the EIO=4 and transport=websocket query parameters. The Socket.IO client adds them for you.

Example complete URL:

wss://channels-ws.moveo.ai/v1/web/1d093558-bac1-4954-acdd-c8d8dc05fa30/ws/?EIO=4&transport=websocket

Required headers​

To upgrade the connection, include the following headers:

  • Connection: upgrade
  • Upgrade: websocket

Connection upgrade response​

Upon successful upgrade, the server responds with an open packet:

0{"sid":SESSION-ID,"upgrades":["websocket"],"pingInterval":10000,"pingTimeout":5000}

Heartbeat​

The server sends a ping packet (2) every pingInterval milliseconds and expects a pong response before pingTimeout.

Message structure​

After connection upgrade, the server only responds to packets prefixed with 4, indicating a message packet type.

The second character of the packet defines the message type:

  • 0: Connect message (server responds with 40{"sid":"SESSION-ID"})
  • 1: Disconnect message
  • 2: Event message (see supported events below)

Event messages must be an array of exactly two elements:

  1. The event type (string), for example, message:send
  2. The event payload (object), for example:
{
"input": {
"text": "defaultstartmessage"
},
"session_id": "5ebeb74f-b3af-4ec0-960f-cd13ad7154d0",
"channel": "web",
"timestamp": 1737028058711
}

Complete example of a message

42["message:send",{"input":{"text":"defaultstartmessage"},"session_id":"5ebeb74f-b3af-4ec0-960f-cd13ad7154d0","channel":"web","timestamp":1737028058711}]

Depending on the event type, the server may respond after processing.

Code example​

This is a comprehensive Node.js example using the socket.io-client library. The example demonstrates:

  • Connection establishment with proper error handling
  • Session creation and management
  • Message sending and receiving
  • Error handling and reconnection logic
  • Logging and monitoring
import { io } from "socket.io-client";

// Configuration
const INTEGRATION_ID = "c3725769-d21e-4391-9f15-63f47eefe211"; // replace with your real one
const URL = `wss://channels-ws.moveo.ai/`;
const MAX_RECONNECT_ATTEMPTS = 5;
const RECONNECT_DELAY = 1000; // 1 second

// Connection options
const socketOptions = {
path: `/v1/web/${INTEGRATION_ID}/ws`,
transports: ["websocket"],
autoConnect: true,
upgrade: false,
extraHeaders: {
Connection: "upgrade",
Upgrade: "websocket",
},
// Reconnection settings
reconnection: true,
reconnectionAttempts: MAX_RECONNECT_ATTEMPTS,
reconnectionDelay: RECONNECT_DELAY,
reconnectionDelayMax: 5000,
};

// Initialize socket connection
const socket = io(URL, socketOptions);

// Connection event handlers
socket.on("connect", () => {
console.log("✅ Connected", socket.id);

// Create a new session
const sessionCreatePayload = {
context: {
user: {
// Add any user-specific context here
email: "user123@example.com",
name: "John Doe",
},
},
timestamp: Date.now(),
is_test: true, // Set to false in production
};

socket.emit("session:create", sessionCreatePayload);
});

// Session management
socket.on("session:created", (data) => {
console.log("🆕 Session created:", data);

// Store session ID for future messages
const sessionId = data.session_id;

// Send initial message
const eventPayload = {
input: {
text: "defaultstartmessage",
},
session_id: sessionId,
channel: "web",
timestamp: Date.now(),
};

socket.emit("message:send", eventPayload);
});

// Message handling
socket.on("message:receive", (data) => {
console.log("📥 Message received:", data);
});

// Error handling
socket.on("connect_error", (err) => {
console.error("❌ Connection error:", err);
});

socket.on("disconnect", (reason) => {
console.log("🔌 Disconnected:", reason);

// Handle specific disconnect reasons
if (reason === "io server disconnect") {
// Server initiated disconnect, try to reconnect
socket.connect();
}
});

// Errors that are not tied to one request
socket.on("app:error", (error) => {
console.error("Server error:", error.error_code, error.description);
});

socket.on("message:send:error", (error) => {
console.error("Message not sent:", error);
});

// Cleanup on process exit
process.on("SIGINT", () => {
console.log("Closing connection...");
socket.close();
process.exit();
});

Limits and error handling​

Limits​

LimitValueWhat happens when a client exceeds it
Size of one WebSocket message100,000 bytesThe server closes the connection with close code 1009.
Text of one message (input.text)1,500 charactersMoveo keeps the first 1,500 characters and drops the rest. The server does not send an error.
User messages in a session200 while the AI agent handles the sessionThe server drops each new message and sends no error. The AI agent does not reply. The limit does not apply after a handover.
Open connectionsA fixed number for each serverThe upgrade request fails with HTTP 503. Connect again with a backoff.
Open connections to one session75session:reconnect, session:continue, and session:history:sync return session:max_concurrent with the session_id, and the connection does not join the session.
session:continue events60 in 60 seconds from one client IP addressMoveo counts these events but does not enforce the limit. When Moveo enforces the limit, the server sends session:continue:error with error_code rate_limited.

The WebSocket API has no other per-connection message rate limit.

Error events​

The server reports an error as an event on the topic of the request, plus :error. For example, a failed session:create returns session:create:error, and a failed file:upload_url:create returns file:upload_url:create:error. A payload that is not valid JSON, or that fails validation, returns app:error:invalid_payload. A server error that is not tied to one request returns app:error. The payload has one of two shapes:

  • An error from the WebSocket server has error_code and description.
  • An error that the Moveo API returns has code, message, and status_code.
error_codeCause
bad-requestThe event or its payload is not valid.
existing-sessionThe request conflicts with a session that already exists.
identity-token-errorThe user authentication token is missing, expired, or not valid.
internal-server-errorThe server could not process the request. Retry with a backoff.
rate_limitedToo many session:continue events from one client IP address, when Moveo enforces that limit.

Handshake errors​

Before the upgrade, the HTTP handshake can fail with one of these responses. The body is JSON with error_code, error_message, and status_code.

HTTP statuserror_codeCause
400bad-requestThe Upgrade header is not websocket, or the EIO or transport query parameter is missing.
400invalid-eio-versionEIO is not 4.
400invalid-transporttransport is not websocket.
403integration-inactiveThe Web integration is not active.
403validation-failedThe integration has a list of domains, and the Origin header is empty or not in the list.
404integration-not-foundNo Web integration has this ID.
503—The server has no free connection. Connect again with a backoff.

Close codes​

The server closes the WebSocket connection with one of these codes:

CodeReason textCause
1000connection close requested from clientThe client sent a Socket.IO disconnect packet (41).
1001server going awayThe server shuts down. Connect again and send session:reconnect.
1009—A WebSocket message is larger than 100,000 bytes.

If the server gets no packet, not even a pong, for longer than pingInterval plus pingTimeout, it closes the connection without a close frame.

Error handling best practices​

  1. Implement exponential backoff for retries
  2. Log errors with appropriate context
  3. Monitor error rates and patterns
  4. Set up alerts for critical errors
  5. Implement circuit breakers for persistent failures

Troubleshooting​

Common issues and their solutions:

  1. Connection failures:

    • Verify the integration ID is correct
    • Check network connectivity
    • Ensure proper headers are set
    • Verify SSL/TLS configuration
  2. Message delivery issues:

    • Check message format and structure
    • Verify session ID is valid
    • Ensure proper event type is used
  3. Performance issues:

    • Monitor connection health
    • Implement reconnection logic
    • Handle backpressure appropriately

Rate limits and best practices​

  1. Connection management:

    • Implement exponential backoff for reconnection attempts
    • Monitor connection health
    • Handle disconnections gracefully
  2. Message handling:

    • Process messages in order
    • Implement message queuing if needed
    • Handle message acknowledgments
  3. Resource management:

    • Close connections when not needed
    • Monitor memory usage
    • Implement proper cleanup procedures