This tutorial will help you to create a contact center based on ACD v1. If you want to create a call center based on ACD v2 (SmartQueue), refer to this guide.
Redirecting an incoming call to a web browser
Answering an incoming call automatically can be useful in some situations, but in the real world, you are most likely want to communicate with the caller and/or connect the caller with other people.
So let’s improve the application created at the previous step by forwarding the user call to a web browser or mobile app. Such a solution is popular among the distributed call centers where operators typically work from home and accept and initiate calls via a web browser. To add the call handling features to a browser, we need two things.
First, the browser should be connected to the Voximplant cloud to be able to accept an incoming call. Second, the browser should have a unique identifier to distinguish it among all the browsers connected to our cloud. Both tasks are solved via our Web SDK. It allows any webpage to establish a real-time connection to the Voximplant cloud. Each connection is identified by the user name.
In the production version, you will definitely use the Web SDK to add voice and video capabilities to your web project. In this example, we will use a pre-built phone interface. Note that this interface is for demonstration purposes only and we cannot guarantee its uptime.
Visit the above webpage and log in using the user name and password you have created previously. Use ‘callcenter’ as the name of the application you have already created at the previous step. Use the account name you have specified at the previous step when you registered at the VoxImplant control panel:
If you receive a login error, it most probably means that there are no applications associated with the user. To form an association, select User on the top menu, click Edit to the right of the user name, select the application from the Applications drop-down list and click Save to confirm the changes. Note that the checkbox "is active" has to be activated.
Logging in from a phone web app will establish a connection from the web browser to the VoxImplant cloud. After that, the webpage can initiate and receive calls. In this example, we will forward all incoming calls to the webpage.
To solve this task, we will need to make a few changes in the existing scenario. First, we need to initiate an outgoing call. There are lots of ways how VoxImplant can initiate calls; in this tutorial, we will use the VoxEngine.callUser method that allows calling a user connected via the web or mobile sdk:
Second, we need to answer the incoming call. In telephony, an incoming call can remain in the unanswered state for some time (we limit this time to 40 seconds). This is called the early media state.
While the call remains in this state, it is not billed but audio can be sent only in one direction — to the caller. Normally, such a state is used to play a progress tone while the call is being forwarded to another person.
The process of adding a progress tone will be covered later in other tutorials. At this step, we will answer the incoming call and make sure that both parties can hear each other. The call is answered via the answer method; audio is sent in both ways via the VoxEngine.sendMediaBetween method. There are more fine-grained methods such as sendMediaTo, which we will examine later:
Call the rented phone number and the Incoming call popup window will appear on the webpage. Click Answer, and you will be able to hear the voice and answer back. This illustrates how calls can be redirected from phones to webpages.
Creating a call queue
The application we created at the previous step has a flaw: it’s unclear what to do if the second user calls while the first one is still talking to the operator. Our web and mobile SDK can accept multiple incoming calls (and the phone app supports two lines to demonstrate it), but a human operator can speak only with one person at a time.
This can be solved by a call queue: while the operator speaks with a user, all other users are waiting in a queue, with optional waiting music being played and/or the synthesized message informing the users about the remaining waiting time.
VoxImplant provides the Call Queue abstraction to automatically handle a queue of incoming calls. To use a queue, you need to create a queue object. But let's deal with the users first. Open Applications in the VoxImplant control panel, and switch to the Users tab and create user1 and user2.
Then go to your application and switch to the Queues tab in it. The queue control interface will be displayed. Click Create queue in the upper right corner (or Create in the center of the screen). At this step, name the queue ‘main’, attach the needed users to it, and click Save:
Modify the code created at the previous step by using enqueueACDRequest instead of callUser and subscribing to the queue events:
With the updated scenario, the second caller will not be connected to the operator until the first finishes his or her conversation. This simple example also has a few pitfalls that you need to keep in mind:
Voximplant webphone has special engines to work with the call queues. The operator needs to change his or her status to ‘ready’ to be able to receive calls. If the operator fails to answer the call, he or she becomes non-responsive and the status is changed to ‘banned’ for some time. Then the operator needs to change the status to ‘online’ and then to ‘ready’.
Up to this step, the scenario doesn’t have any code to handle user disconnections. So, if a user terminates a phone call, the operator will not be disconnected automatically. To accept the second user’s call, the operator needs to manually click Disconnect. At the next step, we will show how you can handle disconnections properly. To troubleshoot the call queue, use the queue control panel interface. Click Refresh to the right of the queue row to see the number of users talking to operators, users waiting in the queue and number of operators. All Voximplant control panel features are also available via HTTP API.
Handling a call disconnect
Since our cloud has separate "incoming" and "outgoing" call logs, we have full control over call disconnects. If a calling user or an operator disconnects, you can make decisions about what to do next: play a notification message, call back, disconnect the remaining participants, and so on. If the incoming or outgoing call is disconnected, the corresponding call object receives the Disconnected event. Please note that an outgoing call can fail to connect (user hasn't answered), in such case Failed event will be received instead of Disconnected.
Given all this information about different ways to disconnect calls and different events that are fired during such disconnects and scenario termination, let’s add "graceful disconnect" to our call center. We will disconnect an operator if a user hangs up, and disconnect a user if an operator hangs up. Modify scenario code by adding Disconnected event handler:
Now if a user or an operator hangs up the call, other party will be gracefully disconnected. Please note, that you are not obliged to disconnect a call and can do any logic: call back, report some statistics, call other person etc. Flexibility of the Voximplant platform allows us to implement any call handling scenario and is not limited to "A calls B, they speak and then the call terminates".
Waiting in a queue
Having full control over incoming and outgoing calls allows implementing any business needs. By default, a user will hear nothing while waiting in the queue, since we have not instructed VoxEngine to produce any audio. A good practice is to inform the user about his or her queue position and play some music to indicate the call in progress.
Let’s start by adding some background music by using the call object’s startPlayback method. In order to start background music, add the following source code:
Important note: outside of conference rooms, any call object can have only one audio source. So if you are using startPlayback and then say, the say method call will detach startPlayback audio and attach it’s own audio. After say finishes, audio from startPlayback will not be automatically attached back.
Music automatically stops after operator answers and the new audio source is connected to call via sendMediaBetween. One more thing to do is queue position notification. This is done by periodically calling a getStatus method of the queue request object and subscribing to the ACDEvents.Waiting event.
The event receives queue position info as position and ewt (estimated wait time) properties of an event handler parameter:
While that setup will work in most situations, where are so-called “edge cases” what can be gracefully handled? For example, if no operators are connected, it’s definitely not possible to queue a request. For such “error cases” ACD module fires a number of events:
It will be a good idea to handle such events and provide the caller with a meaningful way to reach an operator, like asking for permission for callback and passing a phone number to your backend, so an operator can call back manually or automatically later. Complete source code for this step:
IVR and queues
In a simple scenario, all incoming user calls are evenly distributed among all available operators. But as the number of users grows, it becomes more convenient to direct specific requests to specific operators who can handle them better. This raises a number of questions: how to figure out a user question and how to define which operator can answer it.
The second question is related to the queue concept, each queue has some users assigned. After the request is enqueued via enqueueACDRequest, it reaches only the operators that are assigned to a special queue.
To demonstrate how it works, we will implement a simple IVR that will ask: “If you have a warranty question, press 1, otherwise press 2”. Pressing “1” on your phone keyboard will forward you to the operators in the “warranty” queue. Pressing “2” - to any available operator in the "main" queue. In order to use the IVR module, include it into your scenario CommonJS-style:
The IVR module creates a number of linked states and calls the enter method in the root state. Then, depending on the user's choice, he or she will be transferred to an appropriate state. The complete code of the call center code is listed here:
You can control what is happening with your queues in the corresponding section:
Operator status and a temporary ban
While the Voximplant ACD framework provides only an essential call center backbone, it also has some out-of-the-box features for most popular use cases. One of these features is "Operator Status" that can be set to "Ready" if the operator is available to handle a call, or everything referring to non-"Ready" if calls should not be forwarded to this operator.
All statuses except "Ready" and "Offline" works in the same way. Web SDK is used to manage operator status. For example, status can be changed via setOperatorACDStatus method. In our demo webphone, operator status can be changed via a buttons row:
The operator that is not logged in has the "Offline" status. After logging in, the status is automatically changed to "Online". If all operators have the "Offline" status. Please note that queuing a new request will fail with the ACDEvents.Offline event.
Important: Since "Online" is not "Ready", all new logged-in operators will not receive any calls until their status is set to "Ready". This logic is intended to protect new developers from accidental calls to the operators who don't expect them. Status needs to be set to "Ready" either by developer or operator.
Another out-of-the-box feature is "automatic operator ban". If the operator does not answer the call, he or she is marked "banned" and will not receive calls for 12 hours. For each non-answered call the ACDEvents.OperatorFailed event will be triggered and the call will be dispatched to the next available operator. This is the second "safety net" so the calls are not constantly directed to the operators who don't answer them.
In order to "unban" an operator, their status should be changed to "Ready" via Web SDK API. Do it in our phone.voximplant.com example app by clicking on any non-"Ready" status button and then on the "Ready" status button.
Also, all the info about the queue and the operator status can be received via HTTP API. For example, with one "banned" operator and one call waiting, the following response will be received:
Note that the locked_operators list contains the info about unavailable operators. Operators having the unreached field are banned. Other HTTP API methods can be used to manage queues, collect statistics, etc.
Call lists, PDS, and SIP
There are two ways how Voximplant can handle an outgoing call.
Second, you can initiate an outgoing call via the HTTP API. That approach is used if you want to initiate a call from your service or call multiple users. You can implement any call logic via HTTP API, but you also need to set up your own backend that will initiate calls, maintain the suitable number of simultaneous calls etc. For fast "out-of-the-box" experience we have a built-in "Call list" functionality that allows calling thousands of users with a few commands and without any backend of your own.
A call list can be created in the Call Lists section of the control panel or via the CreateCallList HTTP API method. You upload a CSV file with phone numbers and start the calling process with specified options. Each call will trigger a specified VoxEngine scenario that can access the number to call (alongside with any custom data) via the VoxEngine.customData method. You can read more about call lists in this article.
PDS (Predictive Dialing System)
A call list relies on a developer to manually use some Call method if a connected call should be forwarded to an operator.
The predictive dialing feature allows call lists to connect with the automated call distribution system so they work in unison: Voximplant analyses speed at which calls are answered and initiates outgoing calls so call center load is maximized. This feature is automatically enabled if:
- A call list is created with the queue name specified via the queue_id argument.
- After an operator is reached, the reportProgress method should be called. This call is used to calculate operator reach speed and place outgoing calls in a timely manner. Please note that predictive dialing works well only if the call center has a suitable number of operators. Our internal tests show that a reasonable number is 30 operators.
3rd party call control
In real-life scenarios, operators can be connected to the platform via not only Web or mobile SDKs, but also via software or hardware SIP phones. In such cases, call center reps can be still reached via usernames, but how to manage statuses?
Statuses are changed only via the web or mobile SDK. If an operator is connected via SIP, you need to establish a second connection via the web or mobile SDK that will use the same username and password. If multiple connections share the same username, they all will ring on an incoming call, which is inconvenient since the SDK connection is used only to change statuses. For the SDK not to ring on incoming calls, it should init with special receiveCalls flag set to false.