Telephony Preview¶
Status: Current | Last reviewed: 2026-10-20
Use this page when changing AI Studio's expanded Telephony or diagnosing IVR, caller identity, and human-transfer tests. The test phone uses the selected contact-center connection's live routing rather than injecting an AI draft.
Call paths¶
| Provider | Preview entry | Caller identity |
|---|---|---|
| Genesys | Janus → Asterisk outbound SIP → configured BYOC trunk → dialed IVR number | Optional ANI becomes SIP From and P-Asserted-Identity; the trunk must trust it |
| Five9 | Existing emulator SIP route through its configured SBC | Same ANI request; provider policy controls acceptance |
| Amazon Connect | Existing StartWebRTCContact endpoint → selected contact flow → browser Chime audio |
ani and caller_id_number attributes; not a native customer phone endpoint |
PhoneCallTest sends an
explicit telephony call option to
auth-context. That option
bypasses the direct AI WebRTC/LiveKit branches and local AI preflight. It never
attaches X-Pipeline-Id, X-Test-Pipeline-Id, a draft version, or an internal-leg
signature to an external SIP call. Attaching those headers or signing a phone
number as an AI extension would bypass the IVR or fail authorization.
The server resolves the selected tenant-authorized connection and returns
X-Call-Source: standalone-emulator, X-Target-FQDN, and optional
X-Caller-Id-Number. Existing
extensions.conf sets caller identity
before Dial creates the outbound channel, and carries the same ANI as
P-Asserted-Identity. Setting caller identity only in the B-leg header handler
is too late to replace the original SIP From identity. Numbers require an explicit + country
code: numeric-only strings can match an internal extension route.
The auth provider owns both transports, so the phone's mute, DTMF, hangup, busy
state, and recording track getters follow the active call. SIP updatingcall
events generate a JSEP answer and update on the existing handle with no new
tracks. Hold/resume and transfer must not reset the call or stop its recording.
Hangup cancels pending SIP preparation and rejects late offer callbacks.
Connect guards asynchronous SDK/microphone setup with a generation counter,
releases late microphone grants after cancellation, and supplies the local and
remote tracks to recording. The Chime SDK loads only when starting a Connect call.
Controls and discovery¶
Diagnosing intermittent audio¶
SIP Telephony Preview writes a JSON [PreviewAudio] console entry every five
seconds while its call is active. It includes the browser conversation ID,
actual microphone sample rate/channel count and processing flags, the selected
ICE candidate/relay transport, and cumulative WebRTC audio packet, jitter,
concealment and buffer counters. Compare counter deltas within one stream;
jitter and round-trip values are seconds. A stream or peer-connection change
can reset counters. Missing fields mean the browser did not supply them.
The logger reads existing tracks and getStats() only. It does not request a
microphone, process audio, change playback or upload a recording. Device IDs,
device labels, candidate addresses, ICE credentials and TURN URLs are excluded.
Polling ends with the call, and late results from an older SIP attempt are
discarded. Console entries use serialized JSON so copied logs retain values
instead of collapsed Object placeholders.
Correlate a bad call and a known good call by their exact provider conversation
IDs. In Genesys, compare the external PCMU stream with the internal/agent streams;
discardedPackets includes jitter-buffer timing discards and is not a count of
packets lost in transit. Call-wide totals do not locate the fault at transfer.
Compare the provider's separate caller/remote recordings with a bounded passive
packet capture at Asterisk before changing codecs, noise suppression or headset
settings. Installing an audio hook such as MixMonitor can affect bridge
optimization, so document it as a test variable rather than assuming a recorded
and an unrecorded call use identical media handling.
An AI Activity event-stream error is separate from the WebRTC media connection.
Setup controls¶
usePreviewTelephony
loads its catalog only while Telephony is enabled.
PreviewTelephonyControls
uses PreviewControlWidget in the left canvas column, sharing Mock Caller's
rounded shell. Its Integration selector and editable destination combobox show
Genesys numbers with route/flow names, or Connect flow names. Searching and
dropdown browsing share the same input. The list supports arrow keys, Enter,
Escape, and bounded scrolling. These controls render outside the handset shadow
root and remain visible but disabled during calling, connected and recording
states. Manual SIP entry remains available when discovery fails.
The emulator uses initialApp="home" and idleScreen="home_banner" in both
direct and Telephony Preview; its normal start action still calls
handleStartCall, which dispatches the selected external telephony transport.
The in-call PhoneKeypad retains its 80px keys and normal DTMF handling.
The left widget stays outside the phone/AI Activity recording composition.
Connection and destination settings use
sessionStorage key preview.telephony.v1:<tenantId>:<userId>; stale connection
IDs do not fall back to a different destination. Selecting a different connection
clears the previous phone destination and chooses its configured default Connect
flow. Mode state itself is ephemeral. The switch appears only in expanded voice
Preview and is disabled during a call or while Mock Caller is enabled. The mock
transport connects directly to the AI agent and does not support IVR simulation.
phoneLabel is an optional-in-storage display override in the same settings.
Older saved settings hydrate it as an empty string. Empty or whitespace-only
labels display the open agent's name. resolvePreviewTelephonyCall omits the
label from both SIP and Connect call options; it never replaces the destination
or enters provider metadata. The widget disables label editing during calls
and recording.
Collapsing Preview clears every mode switch and ends an active telephony call.
Integration, destination, flow and label settings remain in session storage.
Recording actions and downloads live in PreviewRecordingControls alongside
the Telephony widget, outside the capture. The Preview header stays mounted.
ANI comes from templateVariables.ani, shown with the existing variable editor
in the left controls column. Legacy saved ANI never overrides the current Preview value.
Connect receives other nonempty template variables as contact attributes;
normalized ANI takes precedence over ani and caller_id_number. SIP still
uses only its supported ANI override, without internal agent/template headers.
Variable inputs are disabled while the call is active.
Genesys number discovery reads GET /api/v2/architect/ivrs with server-side
OAuth client credentials. It selects state=active, requires an assigned open,
closed, or holiday flow, flattens dnis, and retains normalized E.164 numbers.
The dropdown searches number, route name, and available flow names locally.
It does not assert that a schedule is open or that an agent is available.
The OAuth client needs routing:callRoute:view in the relevant divisions.
Requests use the exact environments in genesys-regions.json, disallow
redirects, share a 20-second deadline, and read at most 20 pages of 100 routes.
The API reports truncation; it never follows a provider-supplied nextUri.
Missing credentials or discovery permissions do not disable manual dialing.
SIP preparation reads configuration without decrypting OAuth secrets, so discovery
credential failures cannot block that path.
All four Preview endpoints require AIManager:RunAgents (agents:run for
tokens) and tenant context:
| Endpoint | Purpose |
|---|---|
GET /api/preview/telephony/integrations |
Active, supported connection metadata; no config or secrets |
GET /api/preview/telephony/genesys-numbers?integrationId=… |
Routed Genesys numbers |
POST /api/preview/telephony/sip-target |
Validate {integrationId,destination,ani?} and prepare the configured SIP target |
GET /api/preview/telephony/conversation?sessionId=… |
Resolve the exact Genesys or Connect conversation for the current user and tenant's prepared call |
The existing Connect endpoints remain /api/emulator/amazon-connect/contact-flows,
…/webrtc-contact, and …/dtmf.
See API contracts.
Amazon Connect entry paths¶
Confirmed against AWS documentation on October 2, 2026:
StartWebRTCContactcreates the inbound browser audio contact and starts the suppliedContactFlowId. It has contact attributes and participant details, but no customer phone endpoint/ANI argument. This is the existing emulator path reused by Preview.CreateContactsupports VOICE only with initiation methodTRANSFERand subtypeconnect:ExternalAudio. It is not the general browser-call start API.- A SIP-based path exists through the Amazon Chime SDK Voice Connector
CONNECT_CALL_TRANSFER_CONNECTORintegration. AWS documents direct voice and metadata transfer between Connect and other voice systems, including IVR use, but marks it as gated: contact the AWS account team/Connect specialist. The analytics connector is a different integration and does not provide this call-routing path.
Enabling that connector is separate infrastructure work. This Preview feature does not provision it or advertise ordinary phone-number SIP entry for Connect. When native ANI behavior is required, validate the chosen telephony ingress and identity policy end to end instead of substituting a custom contact attribute.
For a flow that transfers browser callers through an existing Voice Connector,
do not bind VoiceConnector.FromUser only to $.CustomerEndpoint.Address.
The October 9 Allianz Preview failures reached Connect successfully, then failed
the transfer with FromUser: "" and took the flow's disconnect branch.
Setting Preview's ANI does not populate that native endpoint.
The separate Allianz - Producer Support flow now resolves
trueserveCallerId before each producer transfer: a native endpoint beginning
with + takes precedence, followed by $.Attributes.ani beginning with +,
then the literal SIP identity anonymous. The transfer reads
$.Attributes.trueserveCallerId. Preview already normalizes entered ANI; the
flow's prefix check selects the source rather than authenticating the caller.
This is a flow correction, not a global default ANI or a new Preview API field.
See the Allianz flow correction and end-session attributes.
Salesforce transfers from Connect Preview¶
SCV inbound routing supports registered WEBRTC_API Preview contacts even
though Connect supplies no native caller or dialed-number endpoints. The
Amazon integration's administrator-owned config.preview_scv_routes maps an
entry flow UUID to {contactCenterId, dnis}. Configure only flows intended
to use Salesforce routing; unmapped flows retain normal Connect Preview behavior.
The Allianz producer mapping uses flow
b566a161-89fa-4e6c-b509-97610bf1aa19, contact center 04vDW0000000AkAYAU
and DNIS +18668985617.
For a mapped flow, the WebRTC start endpoint requires a normalized ANI,
derives DNIS from this mapping, and rejects an explicitly conflicting DNIS.
Before calling AWS it checks the relay's actual contact-center instance, region,
routing enablement and phone allowlist through the service-only
POST /api/sfdc/routing/preview-check. An unavailable relay or invalid mapping
fails before starting a contact. This does not verify customer identity.
After AWS returns its contact ID, Studio stores a six-hour routing binding
alongside the existing Preview ownership record. The relay resolves it using
GET /api/internal/preview/connect-routing?instanceId=…&contactId=…, protected
by SCV_SERVICE_TOKEN. Lookup requires both records and rechecks the current
tenant-visible, active integration and its configured flow mapping. Removing
the mapping or expiring either record revokes the fallback.
SCV_TRANSLATOR_URL in AI Manager identifies the relay's internal HTTP(S)
origin (http://localhost:3031 in Vanguard). The relay uses
AI_MANAGER_INTERNAL_URL (or AI_MANAGER_URL) to call Studio. Both services
need the same existing SCV_SERVICE_TOKEN; keep it in private environment
configuration. These lookups refuse redirects and have five-second deadlines.
The relay uses one resolved caller/destination pair for its number allowlist, VoiceCall creation and Omni Flow request. Native endpoints take precedence; ordinary phone calls do not look up a Preview binding. Caller attributes alone cannot establish a binding. A Preview call still needs the dedicated inbound flow's contact-center assignment, and the mapped DNIS must still be allowed. Case context, duplicate-creation guards and cleanup remain on the existing SCV path. No new Salesforce object or alternate Omni Flow is required.
Primary references:
- Genesys IVR API and schema
- AWS StartWebRTCContact
- AWS StartWebRTCContact request fields
- AWS CreateContact
- AWS Voice Connector integration types and gated access
- AWS SIP integration migration guidance
- Janus SIP re-INVITE protocol
AI Activity and recordings¶
The uncorrelated Genesys AI Activity panel displays Waiting for call to connect to AI agent.
Genesys SIP preparation mints a random previewSessionId, owned by the authenticated
user and tenant in Redis for six hours, and supplies it as X-Conversation-Id.
Asterisk's capture-preview-conversation pre-connect subroutine reads
PJSIP_RESPONSE_HEADER(read,x-inin-cnv) on the answered outbound leg. This is the
Genesys conversation UUID used by the Genesys connector as the TrueServe ID.
The subroutine validates both UUIDs and writes TSF_PREVIEW_<previewSessionId>;
the caller's hangup handler clears that Asterisk global.
The authenticated BFF polls the internal ARI-controller endpoint for this exact
key across configured Asterisk instances. It checks session ownership before
reading, rejects conflicting provider IDs, registers the provider conversation
with the phone authorization registry, and caches the binding for the original
session lifetime. No caller-number/time matching or Genesys API credentials are
needed. ARI_CONTROLLER_URL and ARI_CONTROLLER_INTERNAL_TOKEN must be configured
in AI Manager. Unknown, expired, and other-user/tenant sessions return 404.
For Genesys, telephonyConversationId feeds only AI Activity's passive mode=follow observer;
the primary phone must not activate an AI runtime from the outbound SIP session.
AI Activity connects when the routed TrueServe agent creates its conversation and
shows transcript, tool calls, and persisted Conversation Start/End workflows.
Keep the resolved ID after hangup so end workflows continue updating. A new SIP
call clears it. The provider's published agent runs even when Studio has a draft open.
IVR and human-agent events outside TrueServe are not supplied by this stream.
Five9 does not yet provide this AI Activity correlation.
Connect Preview sends preview: {smsDeliveryMode} to the existing WebRTC start
endpoint. The server chooses a fresh idempotency token, records the returned
ContactId with its user, tenant and integration, and returns previewSessionId
and notificationSessionId. The correlation endpoint waits for a persisted
TrueServe conversation in that tenant whose connect_contact_id or
connect_initial_contact_id matches that exact contact. It follows the first AI
conversation and retains it after hangup; the provider ContactId itself never
activates an AI conversation.
For Voice Connector calls, ARI reads the server-owned
preview:connect:<integrationId>:<contactId> record only after validating the
inbound integration and pipeline tenant. It supplies the existing runtime SMS
delivery and notification-session headers. A bounded wait covers an inbound leg
arriving before the start response is registered; ordinary calls have no
outstanding Preview start and do not wait. Caller-supplied delivery headers
cannot select a Preview session.
With SMS off, authentication and multimodal messages use demo_notification
and arrive in the preview phone's ContactId-scoped notification stream. With
SMS on, the existing real-SMS behavior applies and ANI is required. The
phone's transcript and multimodal surface use the correlated TrueServe
conversation separately in mode=follow. They retain the server's phone
authorization rather than binding the agent currently open in the editor.
These delivery overrides currently cover the Voice Connector → ARI voice path;
Connect KVS-only ingress does not consume them.
The same trusted contact record sets runtime call_source to
ai-manager-telephony-preview, which persists conversations.is_test=true.
The marker is runtime-only: ARI strips it from incoming call-source headers,
keeps its original routing source, and does not grant draft configuration access.
With passkey.simulate_in_preview=true, SMS off and an active test
conversation, authentication emits auth_mode=preview_simulation and opens the
mock ceremony inside the phone browser. Delivery mode alone is insufficient:
the October 10 follow-up received its SMS inside Preview but opened a real
passkey tab because the conversation still had is_test=false. Start a new
call after this correction; existing real passkey links retain their meaning.
The October 10 agent 4873 incident exposed both missing pieces: its 13:46 UTC
Connect call persisted normally, but Preview neither correlated AI Activity nor
passed its simulated-SMS choice. Authentication recorded real_sms and sent
to the customer's stored mobile ending 3123; no demo notification was created.
The correction does not change the published agent or Connect flow.
Long start workflows can accumulate incoming audio before the Live adapter is built. The runtime now includes server-observed setup time in its initial audio buffer budget, preserving those frames and allowing the greeting to start. See GPT Live for buffering and recovery bounds.
Recording reuses the phone/AI Activity crop and MP4 conversion. Caller audio
always passes through the recorder's Krisp noise-cancellation branch; remote
AI/provider audio is mixed directly. This does not replace the live SIP/Connect
tracks. Recording waits for cleanup initialization before starting the call.
Telephony and Recording widgets remain in the left column, outside the capture,
and the variable editor stays below the composition. Both audio tracks come
from the active transport. The routing widget stays mounted but disabled during
a call or recording, preserving the selection for the next test. Repack shared/phone-emulator after editing shared components;
see phone packaging.
Genesys activity stays waiting¶
If the AI answers but Preview has no correlated conversation, first inspect the loaded dialplan:
docker exec tsf-local-asterisk asterisk -rx 'dialplan show capture-preview-conversation'
docker exec tsf-local-asterisk asterisk -rx 'dialplan show ai-manager-outbound'
The capture context must exist, and the outbound Dial must include
U(capture-preview-conversation^${CONVERSATION_ID}). The outbound hangup
extension clears TSF_PREVIEW_<sessionId>. Check this while diagnosing the
actual call: an empty global after hangup is expected, while the Redis session
retains a successfully captured binding.
On October 20, Vanguard had the capture routine in repository source but not in the active or injected Asterisk configuration. Clearway calls produced conversation/tool events, while their Preview sessions never received the provider conversation ID. Installing the capture hook, routine and cleanup in the active/injected dialplan and reloading restored the correlation path. An isolated live check verified Asterisk → ARI → Preview binding, phone stream ownership, retention after hangup and rejection of other users/tenants.
Follow the Asterisk reload procedure.
dialplan reload reads /etc/asterisk/extensions.conf; copying only into
/inject-configs does not activate a change. Keep the active file, saved
template and injected file aligned. Start a new Preview call after repair:
a completed call whose answer was never captured has no recoverable binding.
Never substitute a recent call matched by ANI or time.
Verification¶
Unit coverage pins phone validation, active route filtering, tenant/user storage keys, API payloads, server-side credential handling, and pagination. Browser coverage checks the actual Preview with a simulated Janus provider: dial headers, DTMF, same-call transfer renegotiation, pending-call cancellation, remembered selections, recording layout, Connect flow attributes/errors, exact provider-ID observation, and session ownership/expiry. ARI tests cover UUID validation, multiple instances, ambiguity, and unavailable connections. Automated fixtures do not place calls to external numbers or human agents.
On October 2, 2026, an actual Vanguard Genesys call through agent 4463's published
route resolved its SIP response ID, displayed start workflow actions, delivered
the Denise greeting as browser audio and transcript, displayed the completed
end workflow after hangup, and preserved ANI
+16293034545 through the workflow's matched-account branch.
When the greeting plays but caller speech is missed, inspect the caller recording and media counters separately from the transcript. On October 6, agent 4463 v21 received intelligible quiet speech through Telephony with zero reported packet loss but produced no caller turn. Its publication had inherited a draft-only server voice-isolation filter, absent in v20. Version 22 disables that extra filter while retaining browser microphone processing. A native audio replay alone did not reproduce the same failure consistently; the browser/SIP/Genesys path is required for this regression. See the Takeda runbook for configuration and evidence.
Version 24 restores agent 4463's server filter at strength 50 after matched
recording and live-agent checks. The full-strength replay altered a quiet
opening; the reduced setting retained the tested words while reducing
background level. A published browser Telephony test verified the greeting,
the complete controlled request and an agent response. The per-agent
krisp_viva.noise_suppression_level setting defaults to the previous 100
when absent; other agents' defaults are unchanged.
For a missing greeting, distinguish actual speech from output packet counts. The October 6 13:32 UTC call reached agent 4463 with no connector drops, but low-level startup microphone noise caused the runtime to consume its first greeting without sending it. The corrected initial-connection path preserves buffered audio before sending the enabled greeting; recovery remains separate.
For audio-quality comparisons, download the Genesys recording channels and
align the caller channel with TrueServe's received-caller track. TrueServe's
track is downstream of Genesys, not the original browser microphone.
An October 6 controlled browser tap recovered the same complete phrase at the
browser, Genesys and TrueServe checkpoints, with less than 1 dB spread in
approximate speech RMS. Live captions still changed the opening words.
Older paired recordings also preserved the reported appeal request and pause
phrase despite incorrect live captions. This verifies those sampled words,
not every microphone or call; independent transcription is supporting evidence,
not ground truth. Private paired recordings and a standalone listening report
are in .local-data/takeda-demo/genesys-audio-comparison-2026-10-06/.
For integration acceptance, use a known test route in the target tenant, check the ANI received by the IVR, press a keypad option, route to a staffed queue, and verify two-way audio through hold/resume and agent connection. Record the call and inspect the downloaded MP4. Provider reachability, identity policy, and staffed-agent routing need this live check.