Real-Time Text (RTT/TTY-TDD) Accessibility on Live Voice Calls
Real-time text (RTT) is the modern successor to the telephone-typewriter (TTY/TDD) accessibility channel. It lets a caller or agent exchange text — often character-by-character — on a live call, alongside the audio for a hearing caller or instead of it for a deaf or hard-of-hearing caller. On Orbit, RTT is implemented as RFC 4103 (T.140) text frames carried on the same voice leg, and each frame is recorded per-leg so the agent’s RTT panel and the caller’s endpoint can each see the text as the other party types it. This guide covers how to arm the RTT channel on a live call, how agents and callers exchange text on it, the 2000-character frame ceiling, and how to roll the capability out as a tenant-owned accessibility commitment — not a platform mandate.Prerequisites
- A tenant with the voice/CCaaS pillar enabled.
- The browser softphone or an embedded WebRTC client — RTT opens on the live call, not in a separate chat surface. See Set up the browser (WebRTC) softphone.
1. Arm the RTT channel on a live call
RTT is off for every call until you arm it. Per-call opt-in is deliberate — a contact center treats RTT as a conversation-level flag, not a blanket tenant setting. Three arm paths exist:- From the softphone footer. While a call is answered, click the Real-time text (TTY) toggle to open the panel. The toggle calls
PATCHagainst the call’s RTT config withenabled: trueand pins the panel for that call. - From an IVR or queue step. A flow that takes an inbound call to a queue can open the channel before an agent picks up by posting
PATCH /api/v1/internal/rtt/<call-id>/configwith{ "enabled": true }. The internal HMAC or token credential reaches the config route — not the dashboard session token. Owner: Engineering. - From the agent’s outgoing send. When an agent types the first outgoing line, the send endpoint (
POST /api/v1/voice/calls/<call-id>/rtt/send) accepts the frame and auto-flips the call’s RTT config toenabledon its path — a dashboard agent deliberately typing into the RTT panel is the per-call opt-in, and the softphone makes no separate arm call.
404 when the call does not exist, a 409 with VOICE_RTT_NOT_ENABLED when the auto-arm path fails, and the structured enabled state in the response body on success — never a silent drop.
2. Exchange text on the live call
Once armed, every frame lands on both sides of the conversation:- Caller to agent. The caller’s TDD endpoint (or an app-side WebRTC client) streams text over the in-band T.140 leg. The softphone holds an open SSE connection to
GET /api/v1/voice/calls/:callId/rtt/stream, so the agent sees the caller’s text arriving as it is typed — a per-frame event ordered by the call-relative timestamp. - Agent to caller. The agent’s send endpoint persists the outgoing line and pushes the same frame back over the caller’s endpoint. The body is
{ text, final }—final: falsewhile the agent is still typing (debounced),trueon Enter. Each frame is recorded exactly once.
3. The 2000-character frame ceiling
A single RTT frame is capped at 2000 characters. The ceiling exists to defend against a malformed or hostile endpoint pushing a multi-kilobyte blob into one frame — it mirrors the same kind of cap on the live-interpretation module. Both the inbound caller frame and the outbound agent line are truncated at the frame endpoint, so the persisted row never violates the ceiling and the SSE event never ships a partial frame to the panel. Each persisted row is taggedsource = "rtt_relay" and carries an is_final bit. Replay consumers (QA panels, post-call transcript exports) filter by that tag and sort by segmentStartMs — the same call-relative timeline the speech-to-text and post-call transcript sources use, so RTT rows interleave cleanly in the transcript view.
4. Replay the transcript
Two surfaces read the RTT receipt after the call:GET /api/v1/internal/rtt/<call-id>returns the call’s RTT frames in playback order, cursor-paginated.- The dashboard’s call-details page shows the same receipt on the RTT panel — it reads the persisted rows with
source = "rtt_relay", which keeps RTT frames from mixing into the post-call speech-to-text rows.
5. Roll out as a tenant-owned accessibility gate
The FCC/ADA accessibility commitment for deaf and hard-of-hearing callers sits on each contact center — Orbit is the text-relay surface, not the accessibility mandate. A tenant usually adopts RTT in one of two postures:- Arm-it-on-demand. The softphone, the IVR, or the queue arms the channel per call once an agent flags the caller as a text-relay user. This is the default posture — RTT stays off until something opts in.
- Arm-it-up-front. A flagged accessibility lane opens the config before the call lands on an agent, so every leg already has the channel on.
Worked example — one flagged caller end to end
- The tenant’s CCaaS voice pillar is enabled and the agent’s softphone registers per the browser-softphone guide.
- Phone the tenant’s DID from an outside line. The supervisor flips the Real-time text (TTY) toggle as the call arrives, opening the panel.
- The agent types assistance into the panel; the caller’s text arrives over the SSE stream in the same panel.
- Complete wrap-up. The persisted rows with
source = "rtt_relay"land on the call-details transcript panel, interleaved by timestamp with the speech-to-text rows, and clear on the retention sweep the org already runs.
Related reading
- Set up the browser (WebRTC) softphone — the panel RTT runs in
- Contact-center (voice/CCaaS) go-live runbook — the fuller rollout checklist
- Voice call lifecycle — the receipt side of an RTT frame