Skip to main content

Message Overview

The WebSocket API uses two types of messages:

Text Messages

JSON-formatted control messages for authentication and status

Binary Messages

Raw audio data in PCM format for real-time streaming

Message Direction

Client → Server

  • Authentication Token
  • Audio Data
Message Type: Text (String)
Purpose: Authenticate WebSocket connection
Timing: First message after connection establishment
Format:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkZXZpY2VfNDU2Nzg5MGFiY2RlZjEyMyIsImV4cCI6MTYzOTk4NzY1NCwiaWF0IjoxNjM5OTg3NTk0fQ.signature
Validation:
  • Must be a valid JWT token
  • Token must not be expired
  • Token must contain valid device ID
  • Must be sent within 30 seconds of connection
Example:
websocket.send(jwtToken); // Raw JWT string

Server → Client

  • Connection Confirmation
  • Error Messages
  • Status Messages (Optional)
  • Audio Data
Message Type: JSON Text
Purpose: Confirm successful authentication and connection
Schema:
{
  "type": "savant_voice_connected",
  "message": "string",
  "timestamp": "ISO8601 string",
  "sessionId": "string (optional)"
}
Example:
{
  "type": "savant_voice_connected",
  "message": "Voice API connection established successfully",
  "timestamp": "2024-01-15T10:30:00.123Z",
  "sessionId": "sess_abc123def456"
}
Client Action: Begin audio streaming

Message Validation

Text Message Validation

All text messages must be valid JSON. Invalid JSON will result in immediate connection termination.Valid JSON:
{"type": "vapi_connected", "message": "Connected"}
Invalid JSON:
{type: "error", message: "Missing quotes"} // ❌ Invalid
All JSON messages must include:
  • type field (string)
  • Additional fields based on message type
Missing type field:
{"message": "Connected"} // ❌ Missing 'type'

Binary Message Validation

Binary messages are validated for:
  • Size: Must be divisible by 2 (16-bit samples)
  • Range: Sample values within 16-bit signed range (-32768 to 32767)
  • Frequency: Should maintain ~16kHz equivalent timing
Invalid sizes:
  • 641 bytes (not divisible by 2) ❌
  • 0 bytes (empty audio) ❌
  • 8KB (too large) ❌

Message Flow Examples

Successful Connection

Error Scenario

Implementation Helpers

  • JavaScript
  • Flutter/Dart
class MessageHandler {
  static isTextMessage(data) {
    return typeof data === 'string';
  }
  
  static isBinaryMessage(data) {
    return data instanceof ArrayBuffer;
  }
  
  static parseTextMessage(data) {
    try {
      return JSON.parse(data);
    } catch (e) {
      throw new Error('Invalid JSON message');
    }
  }
  
  static validateMessage(message) {
    if (!message.type) {
      throw new Error('Message missing type field');
    }
    return true;
  }
}

Debugging Messages

Enable Message Logging

websocket.onmessage = (event) => {
  if (typeof event.data === 'string') {
    console.log('Text message:', event.data);
  } else {
    console.log('Binary message size:', event.data.byteLength);
  }
};

Common Issues

Mixed Message Types: Don’t send audio data as text or text as binary - this will cause protocol errors.

Invalid JSON

Always validate JSON before sending text messages

Audio Format

Ensure audio data matches exact PCM specification

Message Order

Send JWT token first, then wait for confirmation

Connection State

Check WebSocket state before sending messages