REST API
WebSocket

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/ws

Authentication

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

ChannelPatternDescription
task:*All task eventsCreated, started, completed, failed, cancelled
task:{id}Specific taskEvents for a single task
plan:*All plan eventsStarted, step completed, completed, failed
plan:{executionId}Specific executionEvents for a single plan execution
hitl:pendingNew approvalsTasks entering HITL queue
hitl:*All HITL eventsPending, approved, rejected, escalated, expired
worker:*Worker eventsConnected, disconnected, heartbeat
queue:{name}Queue eventsTask 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