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/callsSubscribe to real-time call events for the current tenant.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
token | string | JWT 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
| Event | Description |
|---|---|
connected | Connection established successfully |
call.started | New call started |
call.ended | Call ended normally |
call.failed | Call failed |
call.agent_changed | Agent handoff occurred |
call.transcript | New transcript entry |
subscribed | Successfully subscribed to a call |
unsubscribed | Successfully unsubscribed from a call |
ping | Server keepalive ping |
pong | Response to client ping |
error | Error 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"
}
}| Field | Description |
|---|---|
type | Event type identifier |
call_id | Associated call ID (if applicable) |
timestamp | ISO 8601 timestamp |
data | Event-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:
| Parameter | Type | Description |
|---|---|---|
call_id | uuid | The call ID to watch |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
token | string | JWT 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
| Event | Description |
|---|---|
connected | Connection established |
call.status_changed | Call status changed |
call.transcript | New transcript entry |
call.agent_changed | Agent handoff |
call.metrics | Updated 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_xxxxxxxxxxxxxTenant 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
- Use WebSocket for real-time, REST for historical: WebSocket for live dashboards, REST API for analytics
- Implement reconnection logic: Network issues are common, always auto-reconnect
- Handle ping/pong: Respond to server pings to keep connection alive
- Subscribe selectively: Only subscribe to calls you need detailed events for
- Process events asynchronously: Don't block the message handler