SSE for Live Transcripts

View as Markdown

Real-time streaming of user speech (STT) and agent speech (TTS) events for an active call via Server-Sent Events.

Endpoint

GET /api/v1/events?callId={callId}

DetailValue
ProtocolServer-Sent Events (SSE)
AuthenticationCookie-based (logged-in dashboard user)
AuthorizationUser must belong to the org that owns the agent
Content-Typetext/event-stream

Query Parameters

ParameterTypeRequiredDescription
callIdstringYesThe call ID to subscribe events for

Errors

StatusCondition
400Missing or invalid callId
400Call is already completed
404Not authorized / org mismatch
404Call log or agent not found

All events are sent as data: <JSON>\n\n. The three transcript-relevant event types are:

1. user_interim_transcription

Fired as the user is speaking. Contains partial, in-progress transcription text. These events are emitted frequently and may change as more audio is processed.

1{
2 "event_type": "user_interim_transcription",
3 "event_id": "evt_abc123",
4 "timestamp": "2026-03-02T10:00:01.123Z",
5 "call_id": "CALL-1758124225863-80752e",
6 "interim_transcription_text": "I wanted to ask about my"
7}

2. user_transcription

Fired when the user finishes a speech segment. Contains the final transcription for that turn.

1{
2 "event_type": "user_transcription",
3 "event_id": "evt_abc456",
4 "timestamp": "2026-03-02T10:00:02.456Z",
5 "call_id": "CALL-1758124225863-80752e",
6 "user_transcription_text": "I wanted to ask about my recent order"
7}

3. tts_completed

Fired when the agent finishes speaking a TTS segment. Contains the text that was spoken and optionally the TTS latency.

1{
2 "event_type": "tts_completed",
3 "event_id": "evt_abc789",
4 "timestamp": "2026-03-02T10:00:03.789Z",
5 "call_id": "CALL-1758124225863-80752e",
6 "tts_latency": 245,
7 "tts_text": "Sure, I can help you with your recent order. Could you provide your order number?"
8}

Lifecycle Events

sse_init

Sent immediately when the SSE connection is established.

1{
2 "event_type": "sse_init",
3 "event_time": "2026-03-02T10:00:00.000Z"
4}

sse_close

Sent when the call ends, right before the server closes the connection.

1{
2 "event_type": "sse_close",
3 "event_time": "2026-03-02T10:05:00.000Z"
4}

Usage Examples

cURL

$curl -N 'https://api.smallest.ai/atoms/v1/events?callId=CALL-1758124225863-80752e' \
> -H 'Cookie: your_session_cookie' \
> -H 'Accept: text/event-stream'

JavaScript (Browser)

1const callId = "CALL-1758124225863-80752e";
2const evtSource = new EventSource(
3 `/api/v1/events?callId=${callId}`,
4 { withCredentials: true }
5);
6
7evtSource.onmessage = (event) => {
8 const data = JSON.parse(event.data);
9
10 switch (data.event_type) {
11 case "user_interim_transcription":
12 // Update live transcription preview (partial, will change)
13 console.log("[STT interim]", data.interim_transcription_text);
14 break;
15
16 case "user_transcription":
17 // Final user speech for this turn
18 console.log("[STT final]", data.user_transcription_text);
19 break;
20
21 case "tts_completed":
22 // Agent finished speaking this segment
23 console.log("[TTS]", data.tts_text);
24 break;
25
26 case "sse_close":
27 // Call ended, clean up
28 evtSource.close();
29 break;
30 }
31};
32
33evtSource.onerror = (err) => {
34 console.error("SSE connection error:", err);
35 evtSource.close();
36};

Node.js

1import EventSource from "eventsource";
2
3const BASE_URL = "https://api.smallest.ai/atoms/v1";
4const callId = "CALL-1758124225863-80752e";
5
6const es = new EventSource(
7 `${BASE_URL}/events?callId=${callId}`,
8 { headers: { Cookie: "your_session_cookie" } }
9);
10
11es.onmessage = (event) => {
12 const data = JSON.parse(event.data);
13
14 if (data.event_type === "user_transcription") {
15 console.log(`User said: ${data.user_transcription_text}`);
16 }
17
18 if (data.event_type === "tts_completed") {
19 console.log(`Agent said: ${data.tts_text}`);
20 }
21
22 if (data.event_type === "sse_close") {
23 es.close();
24 }
25};

Python

1import json
2import requests
3
4url = "https://api.smallest.ai/atoms/v1/events"
5params = {"callId": "CALL-1758124225863-80752e"}
6headers = {
7 "Cookie": "your_session_cookie",
8 "Accept": "text/event-stream",
9}
10
11with requests.get(url, params=params, headers=headers, stream=True) as resp:
12 for line in resp.iter_lines(decode_unicode=True):
13 if not line or not line.startswith("data: "):
14 continue
15
16 data = json.loads(line[len("data: "):])
17
18 if data["event_type"] == "user_interim_transcription":
19 print(f"[STT interim] {data['interim_transcription_text']}")
20
21 elif data["event_type"] == "user_transcription":
22 print(f"[STT final] {data['user_transcription_text']}")
23
24 elif data["event_type"] == "tts_completed":
25 print(f"[TTS] {data['tts_text']}")
26
27 elif data["event_type"] == "sse_close":
28 print("Call ended.")
29 break

Notes

  • The connection is real-time — events stream directly from the call runtime as they are produced.
  • Interim transcriptions are partial and will be superseded by the final user_transcription event. Use them for live preview UI only.
  • The SSE connection auto-closes when the call ends (sse_close event). The server will also terminate the connection.
  • Only active calls can be subscribed to. Completed calls return a 400 error.
  • Other event types (e.g. call_start, call_end, turn_latency, metrics) are also sent on this stream but are not covered in this doc.