Agent Studio

WebSocket Endpoints

Real-time event streaming via WebSocket

WebSocket Endpoints

WebSocket endpoints for receiving real-time call events. Use these for live dashboards and monitoring.

Call Events Stream

WS /ws/calls

Subscribe to real-time call events for the current tenant.

Query Parameters:

ParameterTypeDescription
tokenstringJWT access token or API key for authentication

Connection Example (JavaScript):

const ws = new WebSocket('wss://api.agentstudio.dev/ws/calls?token=YOUR_TOKEN');

ws.onopen = () => {
  console.log('Connected to call events');
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Event:', data.type, data);
};

ws.onclose = () => {
  console.log('Disconnected');
};

Event Types

EventDescription
connectedConnection established successfully
call.startedNew call started
call.endedCall ended normally
call.failedCall failed
call.agent_changedAgent handoff occurred
call.transcriptNew transcript entry
subscribedSuccessfully subscribed to a call
unsubscribedSuccessfully unsubscribed from a call
pingServer keepalive ping
pongResponse to client ping
errorError message

Event Format

All events follow this format:

{
  "type": "call.started",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:30:00Z",
  "data": {
    "workflow_id": "uuid",
    "workflow_slug": "daily-call",
    "agent_name": "greeter-agent",
    "user_id": "user-123"
  }
}
FieldDescription
typeEvent type identifier
call_idAssociated call ID (if applicable)
timestampISO 8601 timestamp
dataEvent-specific payload

Event Details

call.started

Emitted when a new call starts.

{
  "type": "call.started",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:30:00Z",
  "data": {
    "workflow_id": "uuid",
    "workflow_slug": "daily-call",
    "agent_name": "greeter-agent",
    "user_id": "user-123"
  }
}

call.ended

Emitted when a call completes successfully.

{
  "type": "call.ended",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:33:00Z",
  "data": {
    "duration_seconds": 180,
    "status": "completed",
    "agent_history": ["greeter-agent", "meal-agent"]
  }
}

call.failed

Emitted when a call fails.

{
  "type": "call.failed",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:30:05Z",
  "data": {
    "status": "failed",
    "reason": "Connection timeout",
    "error_code": "TIMEOUT"
  }
}

call.agent_changed

Emitted when a handoff occurs between agents.

{
  "type": "call.agent_changed",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:31:00Z",
  "data": {
    "from_agent": "greeter-agent",
    "to_agent": "meal-agent"
  }
}

call.transcript

Emitted when a new transcript entry is added (only for subscribed calls).

{
  "type": "call.transcript",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:30:10Z",
  "data": {
    "role": "user",
    "content": "I had eggs and toast",
    "agent": "meal-agent"
  }
}

Client Commands

Clients can send commands to the server:

Subscribe to Call

Subscribe to receive detailed events for a specific call:

{
  "type": "subscribe",
  "call_id": "uuid"
}

Response:

{
  "type": "subscribed",
  "call_id": "uuid",
  "timestamp": "2026-01-17T10:30:00Z",
  "data": {
    "message": "Subscribed to call uuid"
  }
}

Unsubscribe from Call

Stop receiving events for a specific call:

{
  "type": "unsubscribe",
  "call_id": "uuid"
}

Keepalive Ping

Send a ping to keep the connection alive:

{
  "type": "ping"
}

Response:

{
  "type": "pong",
  "timestamp": "2026-01-17T10:30:00Z",
  "data": {}
}

Single Call Events

WS /ws/calls/{call_id}

Subscribe to events for a specific call only.

Path Parameters:

ParameterTypeDescription
call_iduuidThe call ID to watch

Query Parameters:

ParameterTypeDescription
tokenstringJWT access token or API key

This endpoint automatically subscribes to the specified call and only receives events for that call.

Event Types for Single Call

EventDescription
connectedConnection established
call.status_changedCall status changed
call.transcriptNew transcript entry
call.agent_changedAgent handoff
call.metricsUpdated metrics

Connection Management

Auto-Reconnection

The server sends keepalive pings every 30 seconds. Implement auto-reconnection in your client:

class CallEventsClient {
  constructor(url, token) {
    this.url = url;
    this.token = token;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectDelay = 3000;
  }

  connect() {
    this.ws = new WebSocket(`${this.url}?token=${this.token}`);
    
    this.ws.onopen = () => {
      this.reconnectAttempts = 0;
      console.log('Connected');
    };

    this.ws.onclose = () => {
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.reconnectAttempts++;
        setTimeout(() => this.connect(), this.reconnectDelay);
      }
    };

    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (data.type === 'ping') {
        this.ws.send(JSON.stringify({ type: 'pong' }));
      }
      this.handleEvent(data);
    };
  }

  handleEvent(event) {
    // Handle events
  }
}

Error Handling

{
  "type": "error",
  "timestamp": "2026-01-17T10:30:00Z",
  "data": {
    "message": "Invalid call_id format"
  }
}

Authentication

WebSocket connections require authentication via the token query parameter:

JWT Token:

wss://api.agentstudio.dev/ws/calls?token=eyJhbGciOiJIUzI1NiIs...

API Key:

wss://api.agentstudio.dev/ws/calls?token=as_live_xxxxxxxxxxxxx

Tenant Isolation

  • Events are scoped to the authenticated tenant
  • You will only receive events for calls belonging to your tenant
  • Subscribing to a call from another tenant will fail silently

Best Practices

  1. Use WebSocket for real-time, REST for historical: WebSocket for live dashboards, REST API for analytics
  2. Implement reconnection logic: Network issues are common, always auto-reconnect
  3. Handle ping/pong: Respond to server pings to keep connection alive
  4. Subscribe selectively: Only subscribe to calls you need detailed events for
  5. Process events asynchronously: Don't block the message handler

On this page