Switchvox PBX Webhook Integration

This document describes the integration between Switchvox PBX Event Triggers and the Heatwave CRM.

Overview

Switchvox can send HTTP POST requests (webhooks) when certain PBX events occur. We use this for:

  1. Voicemail Transcription - When a voicemail is left, we receive notification and transcribe it
  2. Future: Screen Pop - When a call arrives, pop the customer record in CRM
  3. Future: Call Analytics - Track call metrics and outcomes

Architecture

┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│  Switchvox PBX  │──────│  Webhook/Email  │──────│   Heatwave CRM  │
└─────────────────┘      └─────────────────┘      └─────────────────┘
        │                        │                        │
        │  Event Trigger         │                        │
        │  (On New Voicemail)    │                        │
        ├───────────────────────►│                        │
        │  POST /webhooks/v1/    │  WebhookLog + Worker   │
        │  switchvox             ├───────────────────────►│
        │                        │                        │
        │  Email with WAV        │                        │
        ├───────────────────────►│  Action Mailbox        │
        │  voicemail@wy.com      ├───────────────────────►│
        │                        │                        │
        │                        │   CallRecord created   │
        │                        │   + Transcription      │
        │                        │   queued               │
        └────────────────────────┴────────────────────────┘

Voicemail Flow

  1. Caller leaves voicemail on employee's extension
  2. Switchvox sends webhook to /webhooks/v1/switchvox with metadata (caller ID, duration, mailbox)
  3. Switchvox emails voicemail with WAV attachment to voicemail@warmlyyours.com
  4. Action Mailbox (VoicemailsMailbox) receives email, extracts WAV
  5. CallRecord created with call_outcome: :voicemail
  6. Transcription queued via CallRecordTranscriptionWorker
  7. AI analysis runs: transcription → summary → embeddings

Setup Instructions

1. Configure Switchvox Event Triggers

In Switchvox Admin UI:

  1. Go to Setup → Event Triggers
  2. You can set a System Default URL or configure individual event URLs
  3. Use the URL Variables dropdown and Append button to add variables using %VARIABLE_NAME% syntax

Available Variables

Variable Description
CALLER_ID_NAME Caller's name
CALLER_ID_NUMBER Caller's phone number
DIALED_NUMBER Number that was dialed
EVENT_TYPE Type of event
EXTENSION Extension number
EXTENSION_TYPE Type of extension
FEATURE_DATA Additional feature data
INCOMING_DID DID number called
JOB_ID Unique job identifier
QUEUES Queue IDs
VM_DATE Voicemail timestamp
VM_DUR Voicemail duration (seconds)
VM_MAILBOX Mailbox/extension number
VM_MSGNUM Voicemail message number

Recommended URL for "On New Voicemail Event URL"

https://api.warmlyyours.com/webhooks/v1/switchvox?token=YOUR_TOKEN&EVENT_TYPE=new_voicemail&VM_MAILBOX=%VM_MAILBOX%&VM_DUR=%VM_DUR%&VM_MSGNUM=%VM_MSGNUM%&VM_DATE=%VM_DATE%&CALLER_ID_NUMBER=%CALLER_ID_NUMBER%&CALLER_ID_NAME=%CALLER_ID_NAME%

Or use the URL Variables dropdown to append each variable one by one.

Other Useful Event URLs (Future)

On Incoming Call Event URL (for screen pop):

https://api.warmlyyours.com/webhooks/v1/switchvox?token=YOUR_TOKEN&EVENT_TYPE=incoming_call&CALLER_ID_NUMBER=%CALLER_ID_NUMBER%&CALLER_ID_NAME=%CALLER_ID_NAME%&EXTENSION=%EXTENSION%&INCOMING_DID=%INCOMING_DID%&QUEUES=%QUEUES%

On Call Hangup Event URL (for analytics):

https://api.warmlyyours.com/webhooks/v1/switchvox?token=YOUR_TOKEN&EVENT_TYPE=call_hangup&CALLER_ID_NUMBER=%CALLER_ID_NUMBER%&EXTENSION=%EXTENSION%&JOB_ID=%JOB_ID%

2. Configure Voicemail Email Forwarding

In Switchvox Admin UI for each extension:

  1. Go to User Suite → Voicemail & Fax → Notifications
  2. Enable Email Notification for new voicemails
  3. Set email to: voicemail@warmlyyours.com (or voicemail+{extension}@warmlyyours.com)
  4. Enable Attach Voicemail as WAV file

Or configure globally via Admin → Voicemail Settings.

3. Configure Heatwave Credentials

The webhook token is stored in Rails credentials under switchvox.webhook_token:

# In credentials.yml.enc (edit with: rails credentials:edit)
switchvox:
  host: 'p.lz.warmlyyours.net'
  username: 'admin'
  password: 'your_password'
  webhook_token: 'your_secure_token'  # Generate with: SecureRandom.hex(32)

Access via: Heatwave::Configuration.fetch(:switchvox, :webhook_token)

Optionally, configure IP whitelist as an alternative to token auth:

# In Rails console - supports individual IPs and CIDR notation
Setting.switchvox_webhook_ips = ['127.0.0.1', '144.202.57.170', '10.0.0.0/8']

# Initial values seeded via migration (db/migrate/*_seed_switchvox_webhook_ips.rb):
# ['127.0.0.1', '144.202.57.170']

# Validate IPs before saving
invalid = Setting.validate_switchvox_webhook_ips(['192.168.1.1', 'invalid'])
# => ["invalid"]

# Check if IP is in whitelist (used by controller)
Setting.ip_in_switchvox_whitelist?('144.202.57.170')  # => true
Setting.ip_in_switchvox_whitelist?('10.0.0.5')        # => true (if 10.0.0.0/8 in list)

# Empty whitelist = no IP restriction (allows all IPs, rely on token auth)
Setting.switchvox_webhook_ips = []
Setting.ip_in_switchvox_whitelist?('8.8.8.8')         # => true

Note: This setting requires admin role to modify (enforced via CanCanCan).

4. Configure SendGrid Inbound Parse

Ensure voicemail@warmlyyours.com is routed to Action Mailbox:

  1. In SendGrid → Settings → Inbound Parse
  2. Add domain/subdomain if not already configured
  3. URL: https://api.warmlyyours.com/rails/action_mailbox/sendgrid/inbound_emails

Event Variables by Event Type

On New Voicemail

Variable Description Example
VM_MAILBOX Extension/mailbox number 801
VM_DUR Duration in seconds 45
VM_MSGNUM Message sequence number 15
VM_DATE Timestamp 2025-01-21 14:30:00
CALLER_ID_NUMBER Caller's phone number +18005551234
CALLER_ID_NAME Caller's name (if available) John Doe

On Incoming Call

Variable Description
CALLER_ID_NUMBER Caller's phone number
CALLER_ID_NAME Caller's name
DIALED_NUMBER Number the caller dialed
EXTENSION Destination extension
EXTENSION_TYPE Type of extension (sip, queue, ivr, etc.)
INCOMING_DID DID number called
QUEUES Queue IDs if routed to queue
JOB_ID Unique call identifier

On Call Answered / On Call Hangup

Variable Description
CALLER_ID_NUMBER Caller's phone number
CALLER_ID_NAME Caller's name
EXTENSION Extension that handled the call
JOB_ID Unique call identifier
FEATURE_DATA Additional call data

On Agent Logged In / Out

Variable Description
EXTENSION Agent's extension
QUEUES Queue IDs agent logged into/out of

Testing

Test Webhook Endpoint

Note: Switchvox sends GET requests with parameters in the URL. The endpoint accepts both GET and POST.

# With token auth (GET - how Switchvox sends it)
curl "https://api.warmlyyours.me:3000/webhooks/v1/switchvox?token=YOUR_TOKEN&EVENT_TYPE=agent_login&EXTENSION=801&QUEUES=1280"

# Or with POST
curl -X POST "https://api.warmlyyours.me:3000/webhooks/v1/switchvox?token=YOUR_TOKEN" \
  -d "EVENT_TYPE=new_voicemail" \
  -d "VM_MAILBOX=801" \
  -d "VM_DUR=30" \
  -d "VM_MSGNUM=1" \
  -d "CALLER_ID_NUMBER=+18005551234" \
  -d "CALLER_ID_NAME=Test Caller"

Test Action Mailbox

  1. Go to: https://api.warmlyyours.me:3000/rails/conductor/action_mailbox/inbound_emails
  2. Create new inbound email
  3. Set recipient to voicemail@warmlyyours.com
  4. Attach a WAV file
  5. Submit and verify CallRecord is created

Verify Processing

# Check recent webhook logs
WebhookLog.where(provider: 'switchvox').recent.order(created_at: :desc)

# Check recent voicemail call records
CallRecord.where(call_outcome: :voicemail).recent.order(created_at: :desc)

# Check transcription status
CallRecord.where(call_outcome: :voicemail).transcription_eligible

Troubleshooting

Webhook Not Received

  1. Check Switchvox Event Trigger is enabled
  2. Verify URL is accessible from Switchvox server
  3. Check webhook token matches Setting.switchvox_webhook_token
  4. Check WebhookLog for failed entries: WebhookLog.where(provider: 'switchvox', state: 'exception')

Email Not Processed

  1. Check Action Mailbox inbound emails: ActionMailbox::InboundEmail.recent
  2. Verify SendGrid Inbound Parse is configured
  3. Check for failed mailbox processing: ActionMailbox::InboundEmail.failed
  4. Reprocess failed: VoicemailsMailbox.new(ActionMailbox::InboundEmail.find(ID)).process

Transcription Not Running

  1. Check CallRecord has audio: call_record.upload.present?
  2. Check duration: call_record.duration_secs >= 30 (minimum for transcription)
  3. Manually queue: CallRecordTranscriptionWorker.perform_async(call_record_id: ID)
  4. Check Sidekiq for errors in ai_embeddings queue

Files

File Purpose
app/mailboxes/voicemails_mailbox.rb Action Mailbox for voicemail emails
app/controllers/webhooks/v1/switchvox_controller.rb Webhook endpoint
app/services/webhook_processors/switchvox_processor.rb Webhook processing logic
app/services/call_record_processing/transcription_service.rb AI transcription
app/workers/call_record_transcription_worker.rb Background transcription worker
app/controllers/crm/phone_popup_controller.rb Call Pop Up screen pop
app/views/crm/phone_popup/show.html.erb Call Pop Up view

Call Pop Up (Screen Pop)

The Switchvox phone client can open a URL when a call rings, showing caller information in the CRM.

Configuration in Switchvox

  1. Go to AdminPhone SystemEvent TriggersCall Pop Up Settings
  2. Enable Call Pop Up
  3. Set Pop Up When to "Ringing Call"
  4. Set the URL:
https://crm.warmlyyours.com/phone/popup?number=%CALLER_ID_NUMBER%&name=%CALLER_ID_NAME%&did=%INCOMING_DID%

For local testing:

https://crm.warmlyyours.me:3000/phone/popup?number=%CALLER_ID_NUMBER%&name=%CALLER_ID_NAME%&did=%INCOMING_DID%

Available Variables

Variable Description
%CALLER_ID_NUMBER% Caller's phone number
%CALLER_ID_NAME% Caller's name (if available)
%INCOMING_DID% The DID that was called (e.g., 1-800-875-5285)

What the Pop Up Shows

  • Caller Information - Name, phone number, incoming DID
  • CRM Matches - Customers/contacts matching the phone number
  • Quick Actions - Open customer, start new quote
  • Recent Orders - Last 5 orders for matched customer
  • Recent Quotes - Last 5 quotes for matched parties
  • Call History - Recent calls from this number

Endpoint

GET https://crm.warmlyyours.com/phone/popup

Controller: Crm::PhonePopupController#show

Future Enhancements

  1. WebSocket Screen Pop - Use incoming_call webhook + ActionCable to push notification even when CRM isn't focused
  2. Call Analytics - Track call_hangup events for duration, queue wait times
  3. Agent Status Sync - Sync agent login/logout with EmployeePhoneStatus
  4. Realtime API - WebSocket integration for live call status dashboard