WebSocket Events

Event names and payload shapes for realtime signaling.

WebSocket Events

Connect to WebSocket

Use the ws_url returned by POST /v1/call/session-token.

Browser clients cannot set arbitrary Authorization headers on a native WebSocket. Use the JWT subprotocol format:

const socket = new WebSocket(tokenResponse.ws_url, ["jwt", tokenResponse.token]);

Mobile clients may use either the supported subprotocol method above or an Authorization header if their WebSocket library supports it.

Envelope shape

{
  "event": "call.invite",
  "request_id": "req-1",
  "data": {}
}

Core events

EventDirectionPurpose
call.invitecaller -> servicestart outgoing call
call.ringingservice -> calleeincoming call signal
call.acceptcallee -> serviceaccept incoming call
call.rejectcallee -> servicereject incoming call
call.cancelcaller -> servicecancel before connect
call.endeither peer -> serviceend active call
call.connectedeither peer -> servicemark media connected
call.missedservice -> peersmissed timeout fired
call.errorservice -> clientrequest failed
webrtc.offerpeer -> service -> peerSDP offer relay
webrtc.answerpeer -> service -> peerSDP answer relay
webrtc.ice_candidatepeer -> service -> peerICE candidate relay

Invite payload

{
  "callee_user_id": "receiver-456",
  "callee_role": "receiver",
  "context_type": "session",
  "context_id": "SESSION-1001"
}

The service checks that callee_role is inside the JWT allowed_peer_roles. If not, the invite is rejected with:

{
  "event": "call.error",
  "request_id": "req-1",
  "error": {
    "code": "CALL_PEER_ROLE_NOT_ALLOWED",
    "message": "callee role is not allowed by this token"
  }
}

Accept payload

{
  "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134"
}

Reject, cancel, and end payload

{
  "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134"
}

WebRTC offer payload

{
  "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134",
  "sdp": {
    "type": "offer",
    "sdp": "v=0..."
  }
}

WebRTC answer payload

{
  "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134",
  "sdp": {
    "type": "answer",
    "sdp": "v=0..."
  }
}

ICE candidate payload

{
  "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134",
  "candidate": {
    "candidate": "candidate:...",
    "sdpMid": "0",
    "sdpMLineIndex": 0
  }
}

Incoming event examples

auth.ok

Sent after a WebSocket connection is authenticated.

{
  "event": "auth.ok",
  "success": true,
  "data": {
    "user_id": "caller-123",
    "role": "caller",
    "display_name": "Caller One",
    "socket_id": "socket_uuid"
  }
}

call.ringing

Sent to the callee when a caller starts a call.

{
  "event": "call.ringing",
  "data": {
    "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134",
    "caller_user_id": "caller-123",
    "caller_role": "caller",
    "display_name": "Caller One",
    "context_type": "session",
    "context_id": "SESSION-1001",
    "call_type": "audio"
  }
}

call.accepted

Sent to the caller after the callee accepts.

{
  "event": "call.accepted",
  "data": {
    "call_uuid": "78927945-9ff0-4863-89ab-c08cbefed134",
    "status": "accepted"
  }
}