Skip to main content

User WebSocket Stream

Connect to the authenticated user’s real-time event stream. This single connection delivers events for all threads the user participates in.

Endpoint

wss://api.ama2.me/api/v1/chat/ws/user/threads?token=YOUR_JWT_TOKEN

Query Parameters

token
string
required
Valid Supabase JWT token.

Client → Server Messages

Ping (Keep-alive)

{ "type": "ping" }
Server responds with { "type": "pong" }.

Typing Indicator

{
  "type": "typing",
  "data": {
    "thread_id": "uuid",
    "status": "started"
  }
}
status is either "started" or "stopped".

Focus Thread (Presence)

{ "type": "focus_thread", "data": { "thread_id": "uuid" } }

Unfocus Thread

{ "type": "unfocus_thread", "data": { "thread_id": "uuid" } }

Server → Client Events

Thread Message

{
  "type": "thread_message",
  "thread_id": "uuid",
  "data": {
    "id": "uuid",
    "sender_id": "user:uuid",
    "role": "user",
    "content": "Hello!",
    "created_at": "2026-04-09T12:00:00Z"
  }
}

Typing

{
  "type": "thread_typing",
  "thread_id": "uuid",
  "data": {
    "sender_id": "agent:uuid",
    "status": "started"
  }
}

Runtime Events

{
  "type": "thread_runtime",
  "thread_id": "uuid",
  "data": {
    "event_type": "reply_committed",
    "run_id": "uuid"
  }
}

Connection Example

const ws = new WebSocket(
  `wss://api.ama2.me/api/v1/chat/ws/user/threads?token=${jwtToken}`
);

ws.onmessage = (event) => {
  const message = JSON.parse(event.data);
  
  switch (message.type) {
    case "thread_message":
      console.log(`New message in ${message.thread_id}:`, message.data.content);
      break;
    case "thread_typing":
      console.log(`${message.data.sender_id} is typing...`);
      break;
    case "pong":
      break;
  }
};

// Keep alive
setInterval(() => {
  ws.send(JSON.stringify({ type: "ping" }));
}, 30000);