Skip to main content

Error Codes

When an error occurs, the server sends a JSON message with a code and message field before closing the WebSocket.
CodeCauseResolution
AUTH_TIMEOUTToken not sent within 10 seconds of connectingSend the token immediately after the WebSocket opens
INVALID_AUTHFirst message is missing the token fieldEnsure the first message is { "token": "..." }
AUTH_FAILEDToken is invalid or expiredRequest a fresh token and reconnect
SESSION_SETUP_FAILEDServer couldn’t initialize the voice sessionRetry after a short delay

WebSocket Close Codes

CodeMeaning
4001Authentication timeout — token not sent in time
4002Token required — first message was not valid JSON with a token
4003Authentication failed — invalid or expired token
4500Session setup failed — server-side issue
1000Normal close — agent disconnected or session ended

Common Issues

Token Expired

Session tokens are valid for 5 minutes. If you see AUTH_FAILED, your token has likely expired. Always request a fresh token immediately before connecting.

Audio Format Mismatch

The server expects exactly PCM s16le, 16kHz, mono. If the AI agent can’t understand you, verify your audio encoding matches this spec. Common mistakes:
  • Sending Float32 samples instead of Int16
  • Wrong sample rate (e.g., 44.1kHz or 48kHz without downsampling)
  • Stereo audio instead of mono

Microphone Not Working (Web)

Browsers require a user gesture (click/tap) before granting mic access. Also check:
  • The page is served over HTTPS (or localhost)
  • AudioContext is resumed after creation — browsers auto-suspend it
  • The ScriptProcessor output is connected to ctx.destination (required to fire)

Microphone Not Working (Flutter)

Ensure runtime permissions are granted before starting the recorder:
  • Android: RECORD_AUDIO permission in manifest + runtime request
  • iOS: NSMicrophoneUsageDescription in Info.plist
  • Check AudioRecorder.hasPermission() before calling startStream()

WebSocket Connection Refused

Verify the WebSocket URL uses the correct protocol (wss:// for production, ws:// for local development). Use the heartbeat endpoint to confirm the API is reachable.

Reconnection Strategy

Implement exponential backoff when reconnecting after failures:
async function connectWithRetry(maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      await startSession();
      return; // success
    } catch (err) {
      if (attempt === maxAttempts) throw err;
      await new Promise(r => setTimeout(r, attempt * 2000)); // backoff
    }
  }
}

API Reference

POST /api/v1/sdk/token

Creates a voice session and returns a short-lived session token.
# Request
POST /api/v1/sdk/token
Authorization: Bearer <api_key>

# Response 200
{
  "token": "<jwt>",
  "ws_url": "wss://host/api/v1/sdk/ws"
}

POST /api/v1/sdk/heartbeat

Health check — verifies the API is reachable and your API key is valid.
# Request
POST /api/v1/sdk/heartbeat
Authorization: Bearer <api_key>

# Response 200
{ "status": "ok" }