Skip to main content

Live transcript streaming

GET /api/v1/voice/calls/:callId/transcript/stream delivers a call’s transcript utterance by utterance while the call is in progress. It is a one-way Server-Sent Events (SSE) channel for supervisor consoles, QA tooling, and agent-assist integrations that need the words as they are spoken, not a finished document after the call.

Why this surface exists

The stream publishes each partial and final transcript frame as soon as the speech pipeline produces it, with live redaction applied before broadcast. It is deliberately not the post-call pipeline:
  • Post-call transcription and recordings produce a complete transcript once the call ends. Use the recording library when you need the finished, normalised document, search across calls, or exports. The recording lifecycle covers what happens to recordings and their transcripts after hang-up.
  • This surface is live-redact-then-stream. There is no batch step and no webhook delivery: frames only arrive while an SSE connection is open. If your integration can wait for the call to end, use the post-call surfaces instead of holding a stream open.
A delegated supervisor variant with the same contract is available at GET /api/v1/voice/supervisor/calls/:callId/transcript/stream for supervisor views of agent calls. See the supervisor plane model for how delegated supervision is structured.

Endpoint contract

Errors returned before the stream opens: Browser note: when a request includes an Origin header, it must match a trusted Orbit origin or the request is refused with 403 before the stream opens. Server-to-server clients that send no Origin header are unaffected.

Events

Every event carries a monotonically increasing integer id. Lines starting with : are comment keepalives; EventSource ignores them automatically. Keepalive cadence: the server writes a : ping comment every 15 seconds so load balancers and corporate proxies with idle timeouts do not sever the connection during a quiet stretch of an active call.

Transcript frame shape

Lifecycle

On connect the stream writes connected, then status, then a hydration burst of every frame already captured for the call, so a subscriber joining mid-call does not start from a blank slate. If the call is already over (completed, failed, busy, no-answer, or canceled), the server sends the hydration burst followed by end with reason: "terminal" and closes. For a live call the stream stays open until the caller hangs up, the client disconnects, the publisher signals end of transcript, or the 30-minute session cap elapses. After a max-duration end, reconnect; hydration replays the captured transcript so nothing already said is lost.

Redaction guarantees

If your organization has live transcript redaction enabled in its compliance settings (the same policy that governs recording redaction), redaction is applied before broadcast:
  • Every hydrated frame and every live frame is masked before it is written to the stream. The redacted frame is all a subscriber ever sees; with redaction enabled, a spoken payment card number, social security number, phone number, email address, or IP address (or every supported category, when your policy does not restrict the set) never reaches a subscriber.
  • The category set is resolved once, when the stream opens, from the same tenant policy the recording pipeline uses, so the live stream and the stored recording cannot disagree about what is masked.
  • Redaction is a tenant setting, not a client option. Subscribers cannot request more or less redaction per connection, in real time or otherwise; a change to your policy applies to streams opened after the change.
  • When redaction is disabled for your organization, frames pass through unchanged.

Subscribe from a client

Rules for a robust subscriber:
  • The browser EventSource reconnects on its own after a drop. If you build your own client, use exponential backoff capped at roughly 30 seconds, and stop retrying after a terminal end, a terminal: true status, or a 404.
  • Reconnects replay the hydration burst, so de-duplicate against the last frame you rendered. Do not assume a zero gap: frames published while you were disconnected are not re-delivered.
  • Register listeners only for the event names you handle and ignore the rest. New event types may be added over time; treat unknown names as no-ops, never as errors.
  • ?token= puts your key in the URL. Query strings are stripped from access logs platform-wide, but keep the key in server-side or short-lived session contexts in production.

Failure modes

  • The stream closes unexpectedly. Proxies, sleeping laptops, and load balancers all sever SSE connections. Treat any close as recoverable unless it follows end with reason: "terminal" or a 404: reconnect and let hydration restore history.
  • Silence on a live call. Live frames ride a push channel that is not replayed. If the event bus blips, frames published during the blip are not re-delivered; the next reconnect hydrates whatever was captured. A run of : ping keepalives with no transcript events means the connection is healthy; it does not mean speech stopped.
  • Transcription not enabled. When live transcription is off for the call, the stream opens and delivers connected, status, and keepalives, but no transcript events. Silence is a signal: check your transcription configuration (see Live call transcription) rather than the stream.
  • The 30-minute cap. end with reason: "max-duration" is routine housekeeping, not an error. Reconnect to continue.
This surface is SSE only. Orbit does not POST transcript frames to a webhook; a subscriber that needs durability should persist the frames it receives.

Example: supervisor console

Render the rolling transcript alongside the call card:
Because redaction happens before broadcast, the supervisor console above never needs its own masking logic: what the tenant policy masks is what renders.