Skip to main content

Event model

The events channel is your realtime stream for call state updates. Core events:
  • incoming_call
  • call_answered
  • call_ended
  • call_participant_joined
  • call_participant_left
  • call_transcript_delta
  • call_transcript_completed
  • call_ai_audit_event

Authentication model

Use short-lived session_token values minted by your backend. Do not connect browser sockets with publishable keys. Use callUuid as your primary key in client state.
type CallMap = Record<string, {
  callUuid: string;
  status: string | null;
  fromNumber: string;
  toNumber: string;
  startedAt: string | null;
  endedAt: string | null;
}>;

Bootstrap + realtime merge

  1. Load initial call rows from your backend.
  2. Subscribe to realtime events with joinEventsChannel().
  3. Apply event deltas to local cache by callUuid.
  4. Re-fetch on important transitions.

Minimal reducer pattern

function onIncoming(callUuid: string, state: CallMap) {
  const prev = state[callUuid];
  state[callUuid] = {
    callUuid,
    status: "ringing",
    fromNumber: prev?.fromNumber ?? "",
    toNumber: prev?.toNumber ?? "",
    startedAt: prev?.startedAt ?? null,
    endedAt: null,
  };
}

function onAnswered(callUuid: string, state: CallMap) {
  if (!state[callUuid]) return;
  state[callUuid].status = "answered";
}

function onEnded(callUuid: string, state: CallMap, endedAt: string) {
  if (!state[callUuid]) return;
  state[callUuid].status = "completed";
  state[callUuid].endedAt = endedAt;
}

Practical tips

  • Keep event handlers idempotent.
  • Re-mint session tokens on reconnect failures.
  • Handle socket setup failures gracefully and keep UI usable.
  • Session token flow: /guides/realtime-session-tokens
  • Getting started flow: /guides/getting-started-classic
  • RPC action details: /sdk-js/rpc-actions