Build Phone call connectors

What is Phone Connector?

Vtiger has an PhoneCalls module that supports different PhoneCall providers which will help in making outbound and inbound calls from CRM. Right now, it is limited to some providers like Twilio, Plivo, Exotel, Telzio etc. But, we have a lot more Phone Call providers which are not yet available in Vtiger.

Phone Connectors helps you enable below functionality.

  • Click to call
  • Listening incoming calls and show poup inside Vtiger

With a simple xml code we can introduce a new Phone Provider in the PhoneCalls module and connect with telephony providers.

Requirements

Telephony provider should have REST API's support. That's it.

How to build a Phone Connector?

Let's dig in to know how to enable the Phone Connector for the Provider you like.

  1. First you need to access Module Designer, go to the menu check Platform app and under that you can see Module Designer. module_designer

    Here you get an option to add an extension module on the top right corner. Give a name to the module and ignore selecting an App Category.

    create_extension

  2. Adding Connector : VTAP introduced a new Resource type in Module Designer called Connectors - see Adding Connector will prompt for Connector Type and Name where we need to fill details - see

  3. Adding XML configuration : On adding the connector, a default XML template will be loaded which needs to be updated with the provider details which we want to enable - see.

    Let’s go through each XML component that needs our attention


Config

This is where we need to update the fields we need to enable in Settings > Phone Configuration > Provider configuration. We support text, password, url fields in here These are configuration required to make conenction with telephony api's like username, password, or connection keys.

    
<config>
   <fields>
       <field name="username" label="User Name" type="text" >
       <field name="password" label="Password" type="password" >
    <fields>
<config>
    

Provider

We should configure Phone provider endpoint and authentication details here. This is what we use for connecting to the Phone provider service to do call actions.

Any XML component in the connector will accept values from config fields. We have supported tags to access config fields. For instance if we want to access the username field from config then we can use $config.$fields.username We store the connection details using config xml node, then we can use those stored config info using $config.$fields.CONFIG_NAME.

    
<provider>
   <url> https://provider_url <url>
   <auth> 
      <basic username="$config.$fields.username" password="$config.$fields.password">
   <auth>
<provider>
        

outgoing_call

So far we enabled the fields needed and configured the Provider details. Now, it is time to do the action part, configuration that is needed for placing outbound call. This has sub components

  • outgoing_call.request

    • request.url - call provider endpoint for making outbound calls. We can leave this empty if provider url is good enough
    • request.header - if provider is expecting any headers while making a call we can enable those headers here
    • request.parameters - parameters that need to be sent while making a call. We can use config fields if there are any provider account specific parameters. We will have some dynamic parameters that are controlled from Vtiger UI (to, from) for which we can use @to_number, @from_number
  • outgoing_call.response -

    • Response has a format attribute. This helps in identifying the format of response from the Phone provider after placing a call. For now, we only support xml or json format
    • We need to configure the identifiers of response. What key should be considered as call id, status etc. We support nested values as well(for ex:- result.content.call_id)
    • response.call_id - this is used to identify call id from response
    • response.call_status - this is used to identity call status from response
    • response.error - this is used to identify error if call is failed
  • outgoing_call.callbacks -

    • We can remove this component if provider doesn’t support callbacks.
    • Some providers support callback. When call is placed from the CRM, the provider will ring it, once it is answered then it hits the callback url
    • We auto generate callback urls for custom Phone providers. We can use runtime parameter @answer_status_callback if we want to include in request parameters
    • answer_callback:
      • This will be triggered when an outgoing call is answered.
    • answer_callback.response
      • This is used to create phonecall record from the callback request
    • answer_callback.send_response
      • This is used to send response to the callback. Usually phone providers expect some xml to be emitted.
      • Example
    
<answer_callback>
    <response format="json">
        <call_id use="CallSid"><call_id>
        <to_number use="DialTo"><to_number>
        <from_number use="From"><from_number>
        <user_number use="To"><user_number>
        <call_status use="CallStatus"><call_status>
    <response>

    <send_response format="xml" agentdialing="Number">
        <headers>
            <header name="Content-Type" value="text/xml"><header>
        <headers>
        <parameters>
            <parameter name="Dial" >
                <attrs>
                    <attr name="action" value="@status_callback"><attr>
                <attrs>
                <parameter name="Number" value="@to_number"><parameter>
            <parameter>
        <parameters>
    <send_response>
<answer_callback>
    
  • status_callback:
    • This will be triggered when there is change of status for a call
    • status_callback.status
      • Specify for attribute as call statuses that has to be checked before triggering this part.
    • status_callback.status.response
      • This is used to update phone record
      • Example :
    
<status_callback use="CallStatus">
    <status for="completed,hanup">
        <response>
            <call_id use="CallSid"><call_id>
            <call_status use="CallStatus"><call_status>
            <duration use="duration"><duration>
            <starttime use="starttime"><starttime>
        <response>
    <status>

    <status for="in-progress,ringing">
        <response format="json">
            <call_id use="CallSid"><call_id>
            <status use="CallStatus"><to_number>
        <response>
    <status>
<status_callback>
    

This is how outgoing_call going to look after configuring every thing

    
<outgoing_call>
    <request method="get">
        <url>AgentManualDial.php?<url>

        <headers><headers>

        <parameters>
            <parameter name="username" value="$config.$fields.username"><parameter>
            <parameter name="api_key" value="$config.$fields.apikey"><parameter>
            <parameter name="agentID" value="@email"><parameter>
            <parameter name="campaignName" value="@user_phone_home"><parameter>
            <parameter name="customerNumber" value="@to_number"><parameter>
            <parameter name="format" value="json"><parameter>
        <parameters>
    <request>

    <response>
        <error use="message"><error>
        <success use="status"><success>
    <response>

    <callbacks>
        <status_callback use="data.Status">

            <status for="Answered">
                <response>
                    <call_id use="data.monitorUCID"><call_id>
                    <call_status use="completed" default="completed"><call_status>
                    <duration use="data.Duration"><duration>
                    <recordingurl use="data.AudioFile"><recordingurl>
                    <starttime use="data.StartTime"><starttime>
                    <endtime use="data.EndTime"><endtime>
                    <to_number use="data.Did"><to_number>
                    <from_number use="data.CallerID"><from_number>
                    <user_number use="data.AgentID"><user_number>
                    <gateway use="service"><gateway>
                    <direction use="direction" default="outbound"><direction>
                <response>
            <status>

            <status for="NotAnswered">
                <response>
                    <call_id use="data.monitorUCID"><call_id>
                    <call_status use="no-answer" default="no-answer"><call_status>
                    <duration use="data.Duration"><duration>
                    <recordingurl use="data.AudioFile"><recordingurl>
                    <starttime use="data.StartTime"><starttime>
                    <endtime use="data.EndTime"><endtime>
                    <to_number use="data.Did"><to_number>
                    <from_number use="data.CallerID"><from_number>
                    <user_number use="data.AgentID"><user_number>
                    <gateway use="service"><gateway>
                    <direction use="direction" default="outbound"><direction>
                <response>
            <status>
        <status_callback>
    <callbacks>
<outgoing_call>
    

Incoming_call

  • incoming_call.response
    • Response has a format attribute. This helps in identifying the format of response from the Phone provider after placing a call. For now, we only support xml or json format
    • We need to configure the identifiers of response. What key should be considered as call id, status etc. We support nested values as well(for ex:- result.content.call_id)
      • response.call_id - this is used to identify call id from response
      • response.call_status - this is used to identity call status from response
      • response.error - this is used to identify error if call is failed
  • incoming_call.send_reponse
    • This is used to send response to the callback. Usually phone providers expect some xml to be emitted
    • Send Response has a format attribute. This helps in identifying the format of response from the Phone provider after placing a call. For now, we only support xml or json format.
    
<incoming_call>
    <response format="json">
        <call_id use="CallSid"><call_id>
        <to_number use="To"><to_number>
        <from_number use="From"><from_number>
        <gateway use="service"><gateway>
        <direction use="direction" default="inbound"><direction>
    <response>

    //sending response to callback
    <send_response format="xml" agentdialing="Number">
        <headers>
            <header name="Content-Type" value="text/xml"><header>
        <headers>
        <parameters>
            <parameter name="Dial" >
                <attrs>
                    <attr name="statuscallbackurl" value="@answer_status_callback"><attr>
                    <attr name="from_number" value="@from_number"><attr>
                <attrs>
                <parameter name="Number" value="@to_number"><parameter>
            <parameter>
        <parameters>
    <send_response>
<incoming_call>
    

Publish

Once we update the XML with all required details. We are good to go with publishing the connector.

Once we Save and Publish the Connector. We can see a new Provider added in Phone Configuration settings (Settings > Extensions > Phone Configuration) - see

Configure the Provider specific details and activate it.

To test if it's working properly, try Calling to a Contact. Go to the Contacts module, and select the Call option.

Some examples

Twilio
  1. Twilio extension we have developed to give you an idea on how the xml configuration would work, with using the above details: Voice API details for Twilio can be accessed from here

Explanation :

  1. Under config we need details that will help us connect to the APIs using basic authorization. Here authid and authtoken input fields are used to store basic auth details.
  2. In provider we configure the endpoint, auth details which will be picked up from the Settings > Phone Call Settings > Add Provider > Twilio.
  3. In outgoing_call and incoming_call xml will define how the calls will be triggered and show phone call popup.
  4. In outgoing_call request xml node define making POST call to https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Calls.json and passing required parameters
  5. In outgoing_call request will make the actual call to the endpoint, and the response of the request is mapped under response xml node. Assuming the response is json and their keys are mapped to vtiger fields
  6. callbacks are webhook endpoints enabled in the platform to listen on the phone events like answer, call status, hangup event and incoming calls. All these callback response needs to mapped to vtiger relevant fields.
  7. Finally incoming_call listens to inbound calls and sends response back to acknowledge.
       
<?xml version='1.0'?>
<connector for="PhoneCalls">
    <config>
        <fields>
            <!-- CONFIGURE : Data fields that need to be captured from SMS Notifier settings -->
            <field name="authid" label="" type="text">
            <field name="authtoken" label="" type="text">
            <field name="callerid" label="" type="text" presence="mandatory">
            <field name="answer_callback" label="" type="text" presence="mandatory">
            <field name="status_callback" label="" type="text" presence="mandatory">
            <field name="incoming_callback" label="" type="text" presense="mandatory">    
        <fields>
    <config>
    <provider>
        <!-- CONFIGURE : Provider URL -->
        <url> <![CDATA[https://api.twilio.com/2010-04-01/Accounts/$config.$fields.authid]]><url>
        <auth> 
            <!-- CONFIGURE : Credentials -->
            <basic username="$config.$fields.authid" password="$config.$fields.authtoken" >
        <auth>
    <provider>

    <outgoing_call>
        <request>
            <url>Calls.json<url>

            <headers><headers>

            <parameters>
                <parameter name="To" value="@extension"><parameter>
                <parameter name="From" value="@callerid"><parameter>
                <parameter name="Url" value="@answer_callback|urlappend:{'DialTo': '@to_number'}"><parameter>
            <parameters>
        <request>

        <response>

            <callid use="id">
            <status use="callStatus">

            <!-- optional / use from request -->
            <to_number use="To">
            <from_number use="From">

        <response>

        <callbacks>

            <answer_callback>

                <response format="json">
                    <call_id use="CallSid"><call_id>
                    <to_number use="DialTo"><to_number>
                    <from_number use="From"><from_number>
                    <user_number use="To"><user_number>
                    <call_status use="CallStatus"><call_status>
                    <gateway use="service"><gateway>
                <response>

                //sending response to callback
                <send_response format="xml">
                    <headers>
                        <header name="Content-Type" value="text/xml"><header>
                    <headers>
                    <parameters>
                        <parameter name="Dial" >
                            <attrs>
                                <attr name="action" value="@status_callback"><attr>
                            <attrs>
                            <parameter name="Number" value="@to_number"><parameter>
                        <parameter>
                    <parameters>
                <send_response>

            <answer_callback>

            <status_callback use="CallStatus">

                <status for="completed,hangup">
                    <response>
                        <call_id use="CallSid"><call_id>
                        <call_status use="CallStatus"><call_status>
                        <duration use="duration"><duration>
                        <billrate use="billrate"><billrate>
                        <starttime use="starttime"><starttime>
                    <response>
                <status>

                <status for="in-progress,ringing">
                    <response format="json">
                        <call_id use="ParentCallSid"><call_id>
                        <call_status use="CallStatus"><call_status>
                    <response>
                <status>

            <status_callback>

        <callbacks>

    <outgoing_call>

    <incoming_call>
        <response format="json">
            <call_id use="CallSid"><call_id>
            <to_number use="To"><to_number>
            <from_number use="From"><from_number>
            <gateway use="service"><gateway>
            <call_status use="CallStatus"><call_status>
            <direction use="direction" default="inbound"><direction>
        <response>

        //sending response to callback
        <send_response format="xml" agentdialing="Number">
            <headers>
                <header name="Content-Type" value="text/xml"><header>
            <headers>
            <parameters>
                <parameter name="Dial" >
                    <attrs>
                        <attr name="action" value="@status_callback"><attr>
                    <attrs>
                    <parameter name="Number" value="@extension">
                        <attrs>
                            <attr name="action" value="@status_callback"><attr>
                        <attrs>
                    <parameter>
                <parameter>
            <parameters>
        <send_response>

    <incoming_call>
<connector>
    
Ozonetel

Another example developed for Ozonetel provider.

    
<?xml version='1.0'?>
<connector for="PhoneCalls">
    <config>
        <fields>
            <!-- CONFIGURE : Data fields that need to be captured from Phone Configuration settings -->
            <field name="apikey" label="" type="text">
            <field name="username" label="" type="text">
            <field name="callerid" label="" type="text" presence="mandatory">
            <field name="status_callback" label="" type="text" presence="mandatory">
            <field name="incoming_callback" label="" type="text" presence="mandatory">
        <fields>
    <config>
    <provider>
        <!-- CONFIGURE : Provider URL -->
        <url>https://api1.cloudagent.in/CAServices<url>

    <provider>

    <outgoing_call>
        <request method="get">
            <url>AgentManualDial.php?<url>

            <headers><headers>

            <parameters>
                <parameter name="username" value="$config.$fields.username"><parameter>
                <parameter name="api_key" value="$config.$fields.apikey"><parameter>
                <parameter name="agentID" value="@email"><parameter>
                <parameter name="campaignName" value="@user_phone_home"><parameter>
                <parameter name="customerNumber" value="@to_number"><parameter>
                <parameter name="format" value="json"><parameter>
            <parameters>
        <request>

        <response>
            <error use="message"><error>
            <success use="status"><success>
        <response>

        <callbacks>
            <status_callback use="data.Status">

                <status for="Answered">
                    <response>
                        <call_id use="data.monitorUCID"><call_id>
                        <call_status use="completed" default="completed"><call_status>
                        <duration use="data.Duration"><duration>
                        <recordingurl use="data.AudioFile"><recordingurl>
                        <starttime use="data.StartTime"><starttime>
                        <endtime use="data.EndTime"><endtime>
                        <to_number use="data.Did"><to_number>
                        <from_number use="data.CallerID"><from_number>
                        <user_number use="data.AgentID"><user_number>
                        <gateway use="service"><gateway>
                        <direction use="data.Type" default="outbound"><direction>
                        <uui use="data.UUI"><uui>
                        <campaign_name use="data.CampaignName"><campaign_name>
                    <response>
                <status>

                <status for="NotAnswered">
                    <response>
                        <call_id use="data.monitorUCID"><call_id>
                        <call_status use="no-answer" default="no-answer"><call_status>
                        <duration use="data.Duration"><duration>
                        <recordingurl use="data.AudioFile"><recordingurl>
                        <starttime use="data.StartTime"><starttime>
                        <endtime use="data.EndTime"><endtime>
                        <to_number use="data.Did"><to_number>
                        <from_number use="data.CallerID"><from_number>
                        <user_number use="data.AgentID"><user_number>
                        <gateway use="service"><gateway>
                        <direction use="data.Type" default="outbound"><direction>
                        <uui use="data.UUI"><uui>
                        <campaign_name use="data.CampaignName"><campaign_name>
                    <response>
                <status>

            <status_callback>
        <callbacks>

    <outgoing_call>

    <incoming_call>

        <response format="json">
            <call_id use="monitorUcid"><call_id>
            <to_number use="did"><to_number>
            <from_number use="callerID"><from_number>
            <user_number use="agentID"><user_number>
            <call_status use="in-progress" default="in-progress"><call_status>
            <gateway use="service"><gateway>
            <campaign_name use="campaignName"><campaign_name>
            <uui use="uui"><uui>
            <direction use="type" default="inbound"><direction>
        <response>

    <incoming_call>
<connector>