Events: live transcripts and call streaming
Stream live transcripts and call state via WebSocket — render typing indicators, sentiment in real time, or pipe transcripts to your dashboard while the call is ongoing.
Updated May 6, 2026
Events are the live counterpart to webhooks. While webhooks land after-the-fact ("the call ended, here's the summary"), events stream during the call ("here's what was just said").
When to use events
| Scenario | Channel |
|---|---|
| Save transcripts, fire CRM workflows | Webhooks (post-call) |
| Live transcript on a dashboard | Events (during-call) |
| Sentiment / quality scoring after the call | Webhooks |
| Live agent monitoring ("listen-in" UI) | Events |
| Trigger downstream automation when a call ends | Webhooks |
The two channels carry overlapping data; pick based on whether you need realtime or after-the-fact.
Connecting
const url = `wss://api.call2me.app/v1/events?token=${apiKey}`;
const ws = new WebSocket(url);
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', call_id: 'call_xyz789' }));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(msg.type, msg.data);
};
The token in the query string is your API key. For browser clients, issue a short-lived JWT from your backend instead — never expose the API key to a browser.
Event types
| Type | When | Payload |
|---|---|---|
subscribed | Right after subscribe | { call_id } |
transcript.partial | A sentence is being heard | { speaker, text, is_final: false } |
transcript.final | A sentence completed | { speaker, text, is_final: true } |
agent.state | Agent state change | { state: 'listening' | 'thinking' | 'speaking' } |
function.call | Agent invoked a function | { name, args } |
function.result | Function returned | { name, result } |
call.ended | Call finished | { status, duration_ms } |
error | Stream-level error | { code, message } |
transcript.partial events arrive as the speech recognizer ticks; use
them for live "they're typing"-style UI. The transcript.final event
is the ground truth for that utterance.
Subscribing to multiple calls
ws.send(JSON.stringify({ type: 'subscribe', call_id: 'call_a' }));
ws.send(JSON.stringify({ type: 'subscribe', call_id: 'call_b' }));
Events from both calls arrive on the same socket, distinguished by the
call_id field on each message. Useful for monitoring a campaign in
real time.
ws.send(JSON.stringify({ type: 'unsubscribe', call_id: 'call_a' }));
Handling reconnects
On WebSocket close (network blip, mobile-app suspend), reconnect and resubscribe:
let reconnectDelay = 1000;
function connect() {
const ws = new WebSocket(url);
ws.onopen = () => {
reconnectDelay = 1000;
activeSubscriptions.forEach(id =>
ws.send(JSON.stringify({ type: 'subscribe', call_id: id }))
);
};
ws.onclose = () => setTimeout(connect, Math.min(reconnectDelay *= 2, 30000));
}
connect();
Events that fired during the disconnect aren't replayed. For complete history, fetch the transcript via REST after the call ends.
LiveKit data channel
If you're using browser-based voice via LiveKit, transcripts also arrive on the LiveKit data channel — see LiveKit. For phone calls and external monitoring, the WebSocket above is the path.
What's next
Frequently asked
Q.What's the difference between events and webhooks?
Webhooks fire after a discrete event (call ended, transcript completed). Events stream in real time during the call — every utterance as it lands. Use webhooks for downstream workflows; use events for live UI.
Q.Do I need WebSockets to use Call2Me?
No — only if you want live UI. Most integrations work fine with webhooks (server-side) or polling. Events are the optional channel for real-time displays.
Q.Can I subscribe to multiple calls on one connection?
Yes. After connecting, send a subscribe message with a call_id. You can subscribe and unsubscribe to many calls on the same WebSocket.
Q.What if my browser drops the connection?
The platform tracks per-connection state. On reconnect with the same auth, you can resubscribe; you'll get fresh events going forward (history isn't replayed). For replay, fetch the call transcript via REST.