EFSwitch Dialer v1.1
Work In Progress
This document is a work in progress until details have been finalized.
Requirements
To automate outbound communication with customers via interactive voice response (IVR) systems or agents.
Scenario
- The campaign information is specified in the user's campaign manager of choice(Mautic etc).
- This campaign when started is sent to the scheduler which stores the contacts and sends them to CCM at their designated start times.
- CCM feeds contacts one by one to the voice connector which stores them in its own database.
- The dialer periodically runs a query to retrieve pending contacts from the database:
- The total number of contacts to be retrieved depends on the current free call slots.
- These contacts are distributed equally among all campaigns.
- Appropriate action is taken for each contact based on whether its campaign time is AGENT or IVR.
- In case of AGENT campaign call, a payload containing call information is sent to the voice connector which requests an agent from the CCM.
- If an agent is received by the voice connector, the information is sent to the dialer and a call is made to the customer via Freeswitch ESL and bridged to the agent.
- If an agent is not received then the dialer is notified and it sets the contact back to pending again.
- one of the following flows will take place based on the dialing mode:
- PROGRESSIVE: https://docs.expertflow.com/x/pIQMD
- PREVIEW: TBD
- PREDICTIVE: TBD
- In case of IVR campaign call, a call is made to the customer and an IVR menu plays.
- In either case, a post call script ensures that call results are saved in the database.
Flow
Proposed Solution
Contact Structure
The parameters for a campaign contact are set in the campaign manager e.g. Mautic and sent to the scheduler in a payload with the following format:
Campaign contact
{
"id": "aba035c8-b9a9-4d9b-ae40-6fc9a9c02c07", //ID to identify contact
"header": {
"channelData": {
"channelCustomerIdentifier": "1001", //Dialing number of customer
"serviceIdentifier": "1218", //Service identifier of channel connector
"additionalAttributes": []
},
"customer": {
"_id": "61c2b22725dadf1a1050c582"
},
"shedulingMetaData": {
"scheduledDatetime": "2023-04-10T22:55:00+03:00", //Scheduled dial time of this contact
"campaignId": "123456789", //Unique ID for campaign
"campaignType":"TYPE", //Can be AGENT or IVR
"gatewayId": "4d995f13-f90a-4bc9-8045-23809a34f82e", //UUID of SIP gateway through which call will be routed to customer
"campaignContactId": "contact-123", //not in use
"startTime": "2023-04-10T09:00:01+03:00", //Start time for dialing this campaign
"endTime": "2023-04-10T20:00:01+03:00", //End time for dialing this campaign
"priority": "1", //Dialing priority of contact within a campaign
"ivr": "6666", //Used for ivr campaigns, extension number of IVR menu
"dialingMode": "PROGRESSIVE", // Used for agent campaigns, can be PREDICTIVE, PREVIEW or PROGRESSIVE
"routingMode": "QUEUE", //Used for agent campaigns, can be AGENT or QUEUE
"resourceId": "7bn473-c34de35c-v54nv5u43-5dlh68c", //Used for agent campaigns, QUEUE or AGENT ID
"queueName": "", //Used for agent campaigns, queue name i.e. voice queue 4
"webhookId": "KL9DF2", //not in use
"agent": null, //not in use
"queue": null //not in use
}
},
"body": {
"type": "PLAIN",
"markdownText": "Hello Customer"
}
}
These parameters are described in the following sections, along with other relevant information that the dialer stores in a database based on the state of the contact.
Mandatory
Field | Description | Type | Provided By |
---|---|---|---|
id | Unique UUID identifier used to identify this contact and call | VARCHAR(40) | Campaign Manager |
customer_number | The number to be dialed | VARCHAR(20) | Campaign Manager |
campaign_type | IVR or AGENT | VARCHAR(20) | Campaign Manager |
gateway_id | The UUID of the Freeswitch gateway to be used to dial customer number | VARCHAR(40) | Campaign Manager |
status | pending, agent_pending, dialed, ended, stopped or failed | VARCHAR(20) | Dialer |
call_result | The result of a call e.g. Normal clearing, User busy etc | VARCHAR(40) | Dialer |
received_time | The time at which the contact was received from CCM | DateTime | Dialer |
dial_time | The time at which the contact was sent by the dialer to Freeswitch to be dialed | DateTime | Dialer |
campaign_contact_id | The id of the contact received in CCM message payload | VARCHAR(40) | Campaign Manager |
campaign_id | The campaign id received in CCM message | VARCHAR(40) | Campaign Manager |
start_time | The contact cannot be dialed before this time | DateTime | Campaign Manager |
end_time | The contact cannot be dialed after this time | DateTime | Campaign Manager |
priority | The contact between 1-10 | Integer | Campaign Manager |
IVR campaign
Can be provided in an IVR campaign. If not provided, the default value configured in the dialer is used.
Field | Description | Type | Provided By |
---|---|---|---|
ivr | The ivr to be selected, THE IVR number, if contact is IVR based | VARCHAR(20) | Campaign Manager |
Agent campaign
Mandatory for agent campaigns.
Field | Description | Type | Provided By |
---|---|---|---|
dialing_mode | PREDICTIVE, PREVIEW or PROGRESSIVE | VARCHAR(20) | Campaign Manager |
routing_mode | AGENT or QUEUE, only for contacts with campaign_type = AGENT | VARCHAR(20) | Campaign Manager |
resource_id | Queue or AgentId based on routing_mode | VARCHAR(40) | Campaign Manager |
queue_name | The name of queue if routing_mode = QUEUE, optional if routing_mode = AGENT or if routing_mode = QUEUE and resource_id is set | VARCHAR(20) | Campaign Manager |
Dialing Flow
- The dialer will periodically query the database and take note of all the campaigns and the number of their contacts present.
- It will also take note of the current free call slots.
- Based on this information, it will calculate the number of contacts to be retrieved for each campaign such that they are all treated equally.
- A set of queries is then run to retrieve the allotted number of 'pending contacts for each campaign.
- These contacts are then sequentially processed based on the campaign type.
IVR Campaigns
- For IVR based campaigns, the IVR number is taken from the contact entry if set.
- If the IVR number is not provided in the contact entry then the default IVR specified in the dialer configuration is used.
- The dialer checks via Freeswitch ESL if the gateway provided is valid.
If it is valid, then the following command is sent to Freeswitch to initiate the call:
Originate command
JSoriginate {session_in_hangup_hook=true, api_hangup_hook='lua callResults.lua', origination_uuid=call_uuid}sofia/gateway/gateway-id/customerNum IvrNumber XML Freeswitch-IP
- If invalid, the contact status is set to 'failed' and it will not be redialed.
- Once the call ends, a post-call script present on Freeswitch runs automatically and stores the call result to the database and sets the status to 'ended'.
Agent Campaigns
If the campaign call type is of 'AGENT', then the contact status is set to 'agent_pending' and the following payload is posted to the voice connector API:
Call details http://VC-IP-addr:port/fs-message/startprocess
JS{ "callingNumber":"2001",//Customer number "queue":"Voice Queue", //Contains queue name or ID, will use default queue if blank "queueType":"NAME", //Queue identification type, can be NAME or ID "callUid":"8b5342ca-66c1-4d41-a2a1-c04be8ee5228", //Unique ID of call "eslHost":"192.168.1.16", //The IP address of the Freeswitch server through which calls are being routed "serviceIdentifier":"1218", //Service identifier of the voice connector "direction":"OUTBOUND" //Direction of this call, can be DIRECT_TRANSFER, INBOUND or OUTBOUND }
The voice connector sends back the following payload when it received either an agent reserved or no agent available notification from the CCM:
Agent Details for Dialer http://Dialer-IP-addr:port/dialer-connector/agent
JS{ "agent": "2001", //Agent extension, empty when no agent available "uuid": "b07ffee5-b80f-46af-af96-6e57c5030843", //Unique ID of call "queue": "voice Queue 3" //Agent queue name, empty when no agent available }
- If the agent field is empty, this means that no agent was available, so the dialer sets the contact status to 'pending' to try again the next time it queries for pending contacts.
If the agent and queue fields have values then the following command is sent to Freeswitch which will call the customer and bridge the answered call to the agent:
Freeswitch OUTBOUND command
JSoriginate {ignore_early_media=true, session_in_hangup_hook=true, sip_h_X-CallType=PREVIEW, sip_h_X-queueType=NAME, sip_h_X-queue='voice Queue 5', api_hangup_hook='lua callResults.lua', origination_uuid=call_uuid}sofia/gateway/my-gateway/customerNum &bridge(user/agentExtension@eslHost)
If the customer declines the call, the post call script sends an END_CHAT payload to the CCM to close the conversation. In either case it also saves the call result to the database and sets the status to 'ended'.
END_CHAT https://CCM-FQDN/ccm/message/receive
JS{ "id": "1234567", "header": { "channelData": { "channelCustomerIdentifier": "1000", //Customer phone number to be dialed "serviceIdentifier": "1218", //Service identifier of the voice connector "language": {}, "timestamp": 1690437057371, "securityInfo": {}, "intent": "END_CHAT", "sender": { "id": "f1370ff7-43fa-496e-9966-e64061d35f5c", "senderName": "MY_IVR", "type": "IVR" } }, "body": {<irrelevant>} } }
Additional Functions
Campaign controls
The dialer exposes three APIs that can be called by the campaign manager to start, stop or purge campaigns:
- Set this campaign's contacts' status to 'pending' : http://Dialer-IP/dialer-connector/campaign/campaign-id/start
- Set this campaign's contacts' status to 'stopped' (will not be dialed: http://Dialer-IP/dialer-connector/campaign/campaign-id/stop
- Remove all contacts with this campaign ID: http://Dialer-IP/dialer-connector/campaign/campaign-id/purge
Failover Cases
Scenarios | Behavior |
---|---|
The voice connector is down and the agent reservation request cannot be sent to it. | Contact status remains on pending and will be tried again. |
The database is down and dialer cannot retrieve contacts | Dialer will retry on its next cycle. |
Freeswitch gateway is down. | Contact status is set to failed and call result set as Invalid Gateway. |
Freeswitch is down and call command cant be sent. | Contact status is set to failed. |
Campaign manager sends campaign control command(start/stop/purge) to dialer, but database is down. | A Service Unavailable error is returned. |
Campaign manager sends campaign control command to dialer, but no entries with supplied campaign ID are found. | A Not Found error is returned. |
Voice connector sends agent details to dialer but database is down. | A Service Unavailable error is returned. |
Voice connector sends agent details to dialer but an unexpected error occurs e.g. Freeswitch is down. | An Internal Server error is returned. |
Features
- Dialing outbound IVR campaigns.
- Dial out a call to customer and play a specified IVR menu.
- Dialing outbound agent-based campaigns.
- Reserve an agent against a customer, dial a call to the customer, and connect them to the reserved agent.
- Run multiple campaigns simultaneously with a limited number of free call slots.
- Algorithm decides how many calls per campaign to dial out for any given number of free call slots.
- If free slots greater than total campaigns, then contacts are picked from each campaign in order of smallest campaign to largest.
- Within a campaign, contacts are picked according to the FIFO order(queue).
- If free slots lesser than or equal to total campaigns then 1 contact each picked from as many campaigns as there are slots, in order of smallest campaign to largest.
- Record result of each call e.g. Normal clearing, user busy, invalid gateway etc and store in database along with other contact information.
- Send result of each agent-based call as Delivery notifications to EFCX via the voice connector.
- Campaign controls API to :
- Stop pending contacts of a campaign.
- Start stopped contacts of a campaign.
- Purge pending contacts of a campaign.
- API to check current number of ongoing calls.