Softphone Architecture
One-Click Dialing Triggers
Agents can trigger outbound softphone calls from two core CRM profile headers:1. Lead Profile Header
Located inLeadHeaderDetails.tsx, the Direct Call button inspects the lead’s phone number and initiates an outbound session:
- Button State: Displays an animated pulse icon when an outbound call is connecting or active for the lead.
- Payload: Passes
id,name,phone, andtemperatureintouseTelephony().initiateCall. - Keyboard & Screen Reader Accessibility: Includes
aria-label="Call {name} directly via telephony carrier"andfocus-visiblestyling.
2. Broker Profile Header (CP Network)
Located inBrokerHeaderDetails.tsx, Sourcing Managers can call registered Channel Partners directly from their partner profile:
- Button State: Disables during active calls to prevent accidental concurrent dialing.
- Tracking: Links the resulting
CallRecorddirectly tobrokerId.
Floating Active Call Widget
TheActiveCallWidget is rendered globally in apps/web/app/dashboard/layout.tsx. When an agent initiates a call, the widget floats in the bottom-right corner of the viewport and persists across page transitions without interrupting the audio stream.
Call States
The softphone lifecycle transitions through the following explicit states:In-Call Controls
- Mute / Unmute: Toggles the agent’s browser microphone input track using
softphoneEngine.setMuted(boolean). - End Call: Immediately disconnects the active WebRTC session and sends
POST /api/crm/telephony/hangupto release the agent’sisOnCallflag. - Expandable Call Notes: Agents can click Take Call Notes to expand an in-widget scratchpad, write key discussion points while talking to the lead, and save them directly to the lead timeline via
POST /api/leads/:id/notes.
Carrier Modes
The softphone automatically adapts based on the active company carrier configured in Admin Settings:1. In-Browser WebRTC (Twilio Voice SDK)
- Carrier: Twilio.
- Audio Routing: Two-way audio runs directly through the agent’s computer headset or microphone.
- Token Minting: The backend mints an ephemeral JWT Access Token with
VoiceGrantviaCrmTelephonyService.generateAgentToken. - Auto-Provisioning: If Twilio credentials lack a dedicated API Key (
SK...) or TwiML Application (AP...), BrokerOS auto-provisions them programmatically via the Twilio REST API.
2. PSTN Bridged Calling (Exotel / Vobiz / Telnyx)
- Carriers: Exotel (India), Vobiz (India), Telnyx (Global).
- Audio Routing: The carrier dials the customer’s phone and simultaneously rings the agent’s verified personal or office mobile number, bridging the two legs together.
- Recording Callbacks: The carrier records both channels and posts the audio URL to BrokerOS webhooks upon call completion.
3. Local Mock Mode (CRM_MOCK_TELEPHONY=true)
- Enables end-to-end local development and browser testing without live telecom credentials or carrier balance.
- Uses Web Audio API to synthesize ringing and connection tones, creates real
CallRecordentries in PostgreSQL, and generates mock transcripts.
Post-Call AI Processing Pipeline
When the call concludes, the carrier delivers the recording to the BrokerOS webhook:- Carrier Recording Callback: Handled by
CrmTelephonyWebhooksController. - Vercel Blob Upload: The server downloads the MP3 audio buffer and streams it to Vercel Blob Storage under
calls/:targetId-:timestamp-:callRecordId.mp3. - Queue-Based Whisper Transcription:
CallRecordsService.enqueueAudioTranscriptiontranscribes the conversation with Groq Whisper Large v3. - Structured Intelligence Extraction:
- Call Summary: 2 to 3 sentence recap saved to
CallRecord.aiSummary. - Next Step Suggestion: Saved to
Lead.aiNextStepSuggestion. - Extracted Budget & Project: Filled into
lead.budgetandlead.interestedProjectIdfollowing the non-destructive Fill Only If Empty rule.
- Call Summary: 2 to 3 sentence recap saved to