Skip to content

Switchvox PBX Webhook Integration

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

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
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 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 │
└────────────────────────┴────────────────────────┘
  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

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
VariableDescription
CALLER_ID_NAMECaller’s name
CALLER_ID_NUMBERCaller’s phone number
DIALED_NUMBERNumber that was dialed
EVENT_TYPEType of event
EXTENSIONExtension number
EXTENSION_TYPEType of extension
FEATURE_DATAAdditional feature data
INCOMING_DIDDID number called
JOB_IDUnique job identifier
QUEUESQueue IDs
VM_DATEVoicemail timestamp
VM_DURVoicemail duration (seconds)
VM_MAILBOXMailbox/extension number
VM_MSGNUMVoicemail message number
Section titled “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.

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%

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.

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).

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
VariableDescriptionExample
VM_MAILBOXExtension/mailbox number801
VM_DURDuration in seconds45
VM_MSGNUMMessage sequence number15
VM_DATETimestamp2025-01-21 14:30:00
CALLER_ID_NUMBERCaller’s phone number+18005551234
CALLER_ID_NAMECaller’s name (if available)John Doe
VariableDescription
CALLER_ID_NUMBERCaller’s phone number
CALLER_ID_NAMECaller’s name
DIALED_NUMBERNumber the caller dialed
EXTENSIONDestination extension
EXTENSION_TYPEType of extension (sip, queue, ivr, etc.)
INCOMING_DIDDID number called
QUEUESQueue IDs if routed to queue
JOB_IDUnique call identifier
VariableDescription
CALLER_ID_NUMBERCaller’s phone number
CALLER_ID_NAMECaller’s name
EXTENSIONExtension that handled the call
JOB_IDUnique call identifier
FEATURE_DATAAdditional call data
VariableDescription
EXTENSIONAgent’s extension
QUEUESQueue IDs agent logged into/out of

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

Terminal window
# 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"
  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
# 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
  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')
  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
  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
FilePurpose
app/mailboxes/voicemails_mailbox.rbAction Mailbox for voicemail emails
app/controllers/webhooks/v1/switchvox_controller.rbWebhook endpoint
app/services/webhook_processors/switchvox_processor.rbWebhook processing logic
app/services/call_record_processing/transcription_service.rbAI transcription
app/workers/call_record_transcription_worker.rbBackground transcription worker
app/controllers/crm/phone_popup_controller.rbCall Pop Up screen pop
app/views/crm/phone_popup/show.html.erbCall Pop Up view

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

  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%
VariableDescription
%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)
  • 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
GET https://crm.warmlyyours.com/phone/popup

Controller: Crm::PhonePopupController#show

  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