WebSocket API
The WebSocket API provides real-time event streaming for task status updates, plan progress, HITL notifications, and worker health.
Connection
wss://devteam.marsala.dev/wsAuthentication
Include the token as a query parameter or in the first message:
// Query parameter
const ws = new WebSocket('wss://devteam.marsala.dev/ws?token=dtk_live_abc123');
// First message
const ws = new WebSocket('wss://devteam.marsala.dev/ws');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'auth',
token: 'dtk_live_abc123',
}));
};Auth Response
{
"type": "auth:success",
"userId": "usr_001",
"role": "admin",
"timestamp": "2026-02-20T10:00:00Z"
}Subscriptions
After authentication, subscribe to event channels:
Subscribe
{
"type": "subscribe",
"channel": "task:dt_task_abc123"
}Unsubscribe
{
"type": "unsubscribe",
"channel": "task:dt_task_abc123"
}Event Channels
| Channel | Pattern | Description |
|---|---|---|
task:* | All task events | Created, started, completed, failed, cancelled |
task:{id} | Specific task | Events for a single task |
plan:* | All plan events | Started, step completed, completed, failed |
plan:{executionId} | Specific execution | Events for a single plan execution |
hitl:pending | New approvals | Tasks entering HITL queue |
hitl:* | All HITL events | Pending, approved, rejected, escalated, expired |
worker:* | Worker events | Connected, disconnected, heartbeat |
queue:{name} | Queue events | Task added, task started, depth changes |
Event Types
Task Events
{
"type": "task:created",
"taskId": "dt_task_abc123",
"model": "sonnet",
"queue": "default",
"priority": 5,
"timestamp": "2026-02-20T10:00:00Z"
}{
"type": "task:started",
"taskId": "dt_task_abc123",
"workerId": "worker-asus-gpu",
"timestamp": "2026-02-20T10:00:01Z"
}{
"type": "task:completed",
"taskId": "dt_task_abc123",
"output": "Analysis results...",
"usage": { "input": 500, "output": 800, "totalCost": 0.008 },
"durationMs": 3200,
"timestamp": "2026-02-20T10:00:04Z"
}{
"type": "task:failed",
"taskId": "dt_task_abc123",
"error": "Model rate limit exceeded",
"errorCode": "RATE_LIMIT",
"retryCount": 3,
"timestamp": "2026-02-20T10:00:04Z"
}Plan Events
{
"type": "plan:started",
"executionId": "dt_exec_xyz789",
"planId": "dt_plan_abc",
"totalSteps": 4,
"timestamp": "2026-02-20T10:00:00Z"
}{
"type": "plan:step_completed",
"executionId": "dt_exec_xyz789",
"stepId": "extract",
"status": "completed",
"durationMs": 3200,
"progress": { "completed": 1, "total": 4 },
"timestamp": "2026-02-20T10:00:04Z"
}{
"type": "plan:completed",
"executionId": "dt_exec_xyz789",
"totalDurationMs": 15000,
"usage": { "input": 3700, "output": 3500, "totalCost": 0.034 },
"timestamp": "2026-02-20T10:00:15Z"
}HITL Events
{
"type": "hitl:pending",
"taskId": "dt_task_abc123",
"confidence": 0.72,
"summary": "Risk analysis identified 3 high-severity issues",
"planExecutionId": "dt_exec_xyz789",
"stepId": "analyze-risk",
"timestamp": "2026-02-20T10:00:04Z"
}{
"type": "hitl:approved",
"taskId": "dt_task_abc123",
"reviewerId": "reviewer_jane",
"wasModified": false,
"waitTimeMs": 120000,
"timestamp": "2026-02-20T10:02:04Z"
}{
"type": "hitl:escalated",
"taskId": "dt_task_abc123",
"from": "reviewer_bob",
"to": "reviewer_jane",
"reason": "timeout",
"timestamp": "2026-02-20T10:30:04Z"
}Worker Events
{
"type": "worker:connected",
"workerId": "worker-asus-gpu",
"queues": ["gpu-queue", "default"],
"concurrency": 4,
"capabilities": { "gpu": true, "gpuModel": "RTX 5080" },
"timestamp": "2026-02-20T10:00:00Z"
}{
"type": "worker:heartbeat",
"workerId": "worker-asus-gpu",
"activeTasks": 2,
"cpuUsage": 45.2,
"memoryUsage": 68.1,
"timestamp": "2026-02-20T10:00:30Z"
}Heartbeat / Keep-Alive
The server sends a ping every 30 seconds. The client must respond with a pong to maintain the connection.
// Server sends:
{ "type": "ping", "timestamp": "2026-02-20T10:00:30Z" }
// Client responds:
{ "type": "pong" }If no pong is received within 60 seconds, the server closes the connection.
Reconnection
The SDK handles reconnection automatically. For custom implementations:
function connect() {
const ws = new WebSocket('wss://devteam.marsala.dev/ws?token=...');
let reconnectDelay = 1000;
ws.onclose = () => {
setTimeout(() => {
reconnectDelay = Math.min(reconnectDelay * 2, 30000);
connect();
}, reconnectDelay);
};
ws.onopen = () => {
reconnectDelay = 1000;
// Re-subscribe to channels
ws.send(JSON.stringify({ type: 'subscribe', channel: 'task:*' }));
};
}The SDK's client.subscribe() method handles authentication, reconnection, and re-subscription automatically. Use the raw WebSocket API only for non-JavaScript environments.
Next Steps
- Error Codes -- Error handling reference
- SDK Client -- TypeScript WebSocket integration