VoIP API features

Telephony (VoIP) in amoCRM is the integration of amoCRM with a third-party company that provides a virtual telephony service through widgets.

The essence of amoCRM integration and virtual PBX is that data exchange takes place for certain events. There are several such events, the features come from them. Now we will take a look at each feature in detail and give examples of their implementation.

Click 2 call

When a user works in amoCRM, it is possible to request any feature by clicking on the phone number or e-mail address of a contact.

Example of click 2 call

This feature is implemented by the ready-made function add_action ().

Parameters of the function add_action()

Parameter Description
type The type of the transmitted parameter, can be: "email", "phone"
action A function that will be requested when you click on a phone number or email address

Let’s take a look at an example of using the add_action() function by placing it in the init callback function, the callbacks object of the script.js structure. Learn more about the structure of script.js here.

Example

  1. /* script.js */
  2. init: function(){
  3.     self.add_action('phone', function(data){
  4.         self.crm_post (
  5.           'http://127.0.0.1/file.php',
  6.           {
  7.               call_to: data.value
  8.           },
  9.           function(msg){
  10.               alert('Data is sent');
  11.           },
  12.           'text',
  13.           function(){
  14.             alert ('Error');
  15.           }
  16.         );
  17.     });
  18. }

It's important to note that you need to declare the widget's connection point in manifest.json. To perform the function add_action (), you need to set connection points, that contain displayed phone numbers or email addresses. Either set a limited range of trigger points, at your discretion. Read more about the areas of points here. In the example, there are all points where you can find phone numbers and email addresses.

Example

  1. /* manifest.json */
  2. "locations":[
  3.   "ccard-1",
  4.   "clist-1",
  5.   "lcard-1",
  6.   "llist-1",
  7.   "cucard-1",
  8.   "culist-1",
  9.   "comcard-1"
  10. ]

To change the sign on the button that is called when you click on the phone number or email address, it is necessary in the i18n directory of your widget structure, make the appropriate changes in the localization file *.json, as indicated in the example below. If the "call_action" parameter is not set, the name of your widget will be substituted in the button label by default, which is a mandatory parameter in manifest.json. The value of "call_action" will be inserted into the button automatically when the widget is initialized.

Example

  1. /* en.json */
  2. {
  3.   "widget": {
  4.   "call_action": "Call"
  5.   }
  6. }

Incoming call card

There is a feature in amoCRM to display a notification window in the lower right corner. As an example of use, there is an incoming call notification requested by the VoIP.

At the moment of receiving a call to the user's phone, the virtual PBX can request an information about the calling contact via the amoCRM API and transfer it to the user.

To search, you should use the contacts/list method by passing the phone number to the query field. Just like all API methods, this method is requested by an authorized user, and the rights of the user to access contacts are taken into account. So, to identify the caller’s number, this contact must be in the amoCRM database and the corresponding user should have the rights to view the contact card.

It is necessary to set the minimum timeout for querying, since otherwise, in case of degradation of the connection between the PBX and amoCRM, there may be problems with calls.

To deliver an information about an incoming call to a client-side JS script, web-sockets technologies are usually used, when a permanent connection and an event subscription are established between the client and the server. You can use the technology of periodic calls through JS to a third-party server. To do this, every few seconds on the client side, the JS file is loaded from the target server, where an array with the channel state is defined (there is a call; there is no call for a specific internal phone of the user).

The choice of method depends on the technical capability on the side of the virtual PBX to support the web-sockets connection. It is also necessary to take into account the user's internal numbers and their correspondence with the users authorized in amoCRM who are browsing the interface.

Incoming call card example

To implement an incoming call card, you can use the provided object. There is a function created to work with it that you can find in the example.

Example

  1. /* script.js */
  2.  self.add_call_notify = function(data){
  3.         var w_name = self.i18n('widget').name,
  4.         date_now = Math.ceil(Date.now()/1000),
  5.         lang = self.i18n('settings'),
  6.         n_data = {
  7.             from: data.from,
  8.             to: data.to,
  9.             duration: data.duration,
  10.             link: data.link,
  11.             text: w_name + ': ' + data.text,
  12.             date: date_now,
  13.           element: data.element
  14.         };
  15.  /* Check if there is an incoming caller’s contact id in the system */
  16.         if (n_data.element.id > 0){     //If there is an already existing id , create a link for this contact in amoCRM
  17.        text = 'calls: '+n_data.element.name+'</br><a href="/contacts/detail/'+ n_data.element.id+'"> Go to the contact
  18. card</a>';
  19.        n_data.text = text;
  20.        n_data.from = data.from;
  21.          if (n_data.from.length < 4){   //Check for an internal number
  22.             n_data.header = 'Internal number: '+data.from+'';
  23.            }
  24.               else {
  25.                 n_data.header = 'Incoming call: '+data.from+'';
  26.                     }
  27.       }
  28.  AMOCRM.notifications.add_call(n_data);
  29.  };
  30.  /* Data that imitates an incoming information  */
  31.     var notify_data={};
  32.     notify_data.from = '+1 (415) 523 7743';
  33.     notify_data.to = 'Jeff Stevenson';
  34.     notify_data.element = { id: 1003619, type: "contact" };
  35.     self.add_call_notify(notify_data);

The text parameter is required to pass to the add_call function, and if there is a link in it, it should meet the regular expression:(.*href=.*[\?\&]phone=)(.*?)([\&\'\"].*)

In order to find information for a contact with only the phone number of the incoming call, you can use the jquery request.

Example

  1. /* script.js */
  2. var notifications_data = {};
  3. $.get('//'+window.location.host+'/private/api/contact_search.php?SEARCH='+ /*phone number*/ , function(res){
  4.     notifications_data.id = $(res).find('contact > id').eq(0).text();
  5.     notifications_data.name = $(res).find('contact > name').eq(0).text();
  6.     notifications_data.company = $(res).find('contact > company > name').eq(0).text();
  7.     });

It's important to note that you need to declare the widget's connection point in manifest.json. To perform the incoming call card function, it is recommended to set the everywhere point. It defines that your widget will work in any point of amoCRM, it will allow you to receive notifications of an incoming call, regardless of the user's work in amoCRM. For more information about the connection points, click here.

Example

  1. /* manifest.json */
  2. "locations":[
  3.                 "everywhere"
  4.             ]

You can also display the information about a completed call by passing the incoming data:

Example

  1. /* script.js, changed input data */
  2. var notify_data={};
  3. notify_data.from = 'Jack Nicholson';
  4. notify_data.to = 'Jeff Stevens';
  5. notify_data.element = { id: 1003619, type: "contact" };
  6. notify_data .duration = 60,
  7. notify_data.link = 'https://example.com/dialog.mp3';
  8. notify_data.text = 'Widget text';

Example of changed input data

Creating a contact card

In the amoCRM, you can create a contact card, if an incoming call comes from a contact that is not yet in your account.

Notification Example

To implement this feature, it is necessary to make changes to the method described in the "Incoming call card".

Example

  1. self.add_call_notify = function(data){
  2.         var w_name = self.i18n('widget').name,
  3.             date_now = Math.ceil(Date.now()/1000),
  4.             lang = self.i18n('notifications'),
  5.             text,
  6.             n_data = {
  7.                 to: data.to,
  8.                 duration: data.duration,
  9.                 date: date_now,
  10.                 n_data.element = data.element
  11.             };
  12.       /* Check if there is an incoming caller’s contact id in the system */
  13.      if (n_data.element.id > 0){  //If there is an already existing id , create a link for this contact in amoCRM
  14.        text = 'Calls you: '+n_data.element.name+'<a href="/contacts/detail/'+ n_data.element.id+'"> Go to the contact
  15. card</a>';
  16.        n_data.text = text;
  17.        n_data.from = data.from;
  18.          if (n_data.from.length < 4){   //A check for an internal number
  19.               n_data.header = 'Internal number: '+data.from+'';
  20.            }
  21.            else {
  22.                 n_data.header = 'Incoming call: '+data.from+'';
  23.                 }
  24.      }
  25.           else {  //If there is no ID, then form a link to create a new contact
  26.             text = '<a href="/contacts/add/?phone='+ data.from+'">Create a contact</a>';
  27.             n_data.text = text;
  28.             n_data.header = 'Incoming call '+ data.from+'';
  29.       //Please note, that if you create a new contact, n_data.from is not filled in!
  30.           }
  31.     AMOCRM.notifications.add_call(n_data);
  32. };
  33.    /* Data that imitates an incoming information */
  34.     var notify_data={};
  35.     notify_data.from = '+1 (415) 523 77 43';
  36.     notify_data.to = 'User Name';
  37.     self.add_call_notify(notify_data);

Smart forwarding

When you receive a call, in addition to the caller name information, you can also get the amoCRM user ID who is responsible for the caller's contact card. From the account information you can get the phone number of the responsible user and forward the call to the person who works with the contact.

To implement this feature, you will need to make several queries to our API in order to get the phone number of the user responsible for the calling contact card.

Example

  1. $phone_number = /* Incoming call phone number */;
  2. $subdomain = /* Your account — subdomain */;
  3. $link='https://'.$subdomain.'.amocrm.com/private/api/v2/json/contacts/list?query='.$phone_number;  //API request for a search of contact card
  4. $curl=curl_init(); #Save cURL session descriptor
  5. #Set necessary options for cURL session
  6. curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
  7. curl_setopt($curl,CURLOPT_USERAGENT,'amoCRM-API-client/1.0');
  8. curl_setopt($curl,CURLOPT_URL,$link);
  9. curl_setopt($curl,CURLOPT_HEADER,false);
  10. curl_setopt($curl,CURLOPT_COOKIEFILE,dirname(__FILE__).'/cookie.txt');
  11. curl_setopt($curl,CURLOPT_COOKIEJAR,dirname(__FILE__).'/cookie.txt');
  12. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,0);
  13. curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,0);
  14. $out=curl_exec($curl); #Initiate an API request and save a response in a variable
  15. $code=curl_getinfo($curl,CURLINFO_HTTP_CODE);
  16. curl_close($curl);
  17. $Response=json_decode($out,true);
  18.         /* We receive a responsible user ID,  from a response of a user card request */
  19.        $responsible_user_id = $Response['response']['contacts'][0]['responsible_user_id'];

$responsible_user_id is the ID of the user responsible for the card of the contact making the call. Because the user data in the amoCRM account and in the database of the VoIP widget match, which is one of the conditions for connecting the VoIP widget, you can transfer the incoming call to the responsible user.

Call result

The feature is implemented by launching a modal window in which you can create a new lead or contact, specifying a note or to-do that will be associated with the created entity.

Example of a call result

Please note that in order to successfully launch the modal window, your widget’s script should start as shown in the example below.

Example

  1. define(['jquery', 'lib/components/base/modal'], function($, Modal){
  2.     /* Here is your widget’s script */
  3. });

As an example of implementing this feature, we create a modal window with a markup for entering information and describe the requests to the API for adding information to the database. For more information about the structure of requests for adding entities via API requests, read here.

Example

  1. setTimeout(self.call_result,30000); //set a function request delay for the call result feature
  2. this.call_result = function() {
  3. /* Compose the markup of the data entry form, which will be displayed in the modal window */
  4.     var data = [];
  5.   data.push('<style type="text/css" style="display: none">'+
  6.     'input[type="text"] {'+
  7.       'border: 1px solid #696969;'+
  8.       'border-radius: 3px;'+
  9.       '-webkit-border-radius: 3px; //rounding of corners (Google Chrome)'+
  10.       '-moz-border-radius: 3px; //rounding of corners (FireFox)'+
  11.       'margin: 2px;'+
  12.       'padding: 2px'+
  13.     '}'+
  14.     'input[type=submit] {'+
  15.       'background-color: #20B2AA;'+
  16.       'border: 1px #008B8B;'+
  17.       'border-radius: 3px;'+
  18.       'padding: 3px'+
  19.     '}'+
  20.   '</style>'+
  21.   '<form method="post" name="lead_data" id="call_result_data">'+
  22.     '<label for="inputs">Call result +1(415)523-77-43</label><br><br>' +
  23.       '<div id="inputs">'+
  24.           '<input id="contact" type="text" name="contact_name" placeholder="Contact’s name"><br><br>'+
  25.         '<input id="lead" type="text" name="lead_name" placeholder="Lead name"><br><br>'+
  26.         '<input id="lead_note" type="text" name="note" placeholder="Note"><br><br>'+
  27.         '<label for="lead_task">To-do type</label><br>'+
  28.           '<select name="task_type">'+
  29.             '<option value=1>Follow-up</option>'+
  30.             '<option value=2>Call</option>'+
  31.             '<option value=3>Meeting</option>'+
  32.             '<option value=4>Email</option>'+
  33.           '</select><br><br>'+
  34.         '<label for="lead_task_text">Set a To-do</label><br>'+
  35.         '<input id="lead_task_text" type="text" name="text" placeholder="To-do"><br><br>'+
  36.       '</div>'+
  37.     '<input type="submit" value="Save">'+
  38.   '</form>');
  39.   modal = new Modal({
  40.     class_name: 'modal-window',
  41.     init: function ($modal_body) {
  42.       $modal_body
  43.       .trigger('modal:loaded') //it starts a modal window displaying
  44.       .html(data)
  45.       .trigger('modal:centrify')  //it configures the modal window
  46.       .append('<span class="modal-body__close">Cancel</span>');
  47.     },
  48.     destroy: function () {
  49.     }
  50.   });
  51.   $('#call_result_data input[type="submit"]').click(function(e) {
  52.     e.preventDefault();
  53.     var data;   // a variable which will contain a serialization data
  54.     data = $(this).parent('form').serializeArray();
  55.     setTimeout('$(".modal-body__close").trigger("click")',1000);
  56.       if(data[1]['value'] != ""){
  57.         var lead_data = [];
  58.                     lead_data = {
  59.                         "request":  {
  60.                             "leads":  {
  61.                                 "add":  [{
  62.                                     "name":data[1]['value']
  63.                                 }]
  64.                             }
  65.                         }
  66.                     };
  67.                 $.post('https://cnst.amocrm.com/private/api/v2/json/leads/set', lead_data, function(response) {
  68.               var lead_id = response.response.leads.add[0].id;    
  69.                       if(lead_id != 0) {
  70.                         if(data[0]['value'] != ""){
  71.                                 var contact_data = [],
  72.                                 task_data = [],
  73.                                 note_data = [];
  74.                                 contact_data  = {
  75.                                     "request":  {
  76.                                         "contacts":  {
  77.                                             "add":  [{
  78.                                                 "name":data[0]['value'],
  79.                                             "linked_leads_id": lead_id
  80.                                         }]
  81.                                     }
  82.                                 }
  83.                             };
  84.                         $.post('https://cnst.amocrm.com/private/api/v2/json/contacts/set', contact_data, function(response)
  85. {
  86.                           var contact_id = response.response.contacts.add[0].id;
  87.                     }, 'json');}
  88.                     if(data[3]['value'] != ""){
  89.                             task_data = {
  90.                                 "request":  {
  91.                                     "tasks":  {
  92.                                         "add":  [{
  93.                                             "element_id":  lead_id,
  94.                                             "element_type":  2,
  95.                                             "task_type": data[3]['value'],
  96.                                             "text":  data[4]['value']
  97.                                         }]
  98.                                     }
  99.                                 }
  100.                             };
  101.                     $.post('https://cnst.amocrm.com/private/api/v2/json/tasks/set', task_data, function(response) {},
  102. 'json');}
  103.                         if(data[2]['value'] != ""){
  104.                                 note_data = {
  105.                                     "request":  {
  106.                                         "notes":  {
  107.                                             "add":  [{
  108.                                                 "element_id":  lead_id,
  109.                                                 "element_type":  2,
  110.                                                 "note_type":  4,
  111.                                                 "text":  data[2]['value']
  112.                                             }]
  113.                                         }
  114.                                     }
  115.                                 };
  116.                         $.post('https://cnst.amocrm.com/private/api/v2/json/notes/set', note_data, function(response) {},
  117. 'json');}
  118.                         }
  119.                 }, 'json');
  120.       }
  121.   });
  122. };

Call logging

Call logging is being done in the events of the corresponding contact, in the corresponding types of outgoing and incoming call events. If the PBX supports call recording, the user will see a link and a player to listen to the call recording.

  • via the notes method (Add events)
  • via the calls/add method (Add calls)

It's simpler to add a call as a note. This does not require a special service key. However, to add a call via notes, you must pass element_id of the contact card. The calls/add method does not require this parameter. It’s searching for the contact card itself.

To add records to events, you should use the calls/add method. In this case, events are added only to an existing contact found by the phone number. Therefore, we mark in the database sent and not sent records of calls. And we try to add not sent calls (cards for which have not yet been created) once again within 18 hours. If the contact card is not created 18 hours later, then the call will not be added to the system.

The result of adding calls that is displayed in the contact card

Error message

In order to notify the user about the problems that occur in background processes, it is necessary to use a separate JS-object that will display an error message to the user when he makes a call. For example, an error message about a failed connection to the server.

We recommend using such notifications if JS on the page performs some background actions (they are requested as hidden from the user, not by his request). In such cases, you can notify the user that something went wrong and what actions he needs to take.

Error message example

Parameters

Parameter Type Description
header string Widget’s name will be displayed in the headline
text string Error message
date timestamp Date

callbacks: object of callback functions. When you add a new message or an error occurs, the AJAX request is passed to the server, which returns the number of this message if the data is successfully saved. Depending on the success of the request, one of the passed functions of this object is triggered.

Example

  1. var  errors = AMOCRM.notifications,
  2.     date_now = Math.ceil(Date.now()/1000),
  3.     header = self.get_settings().widget_NAME,
  4.     text = 'error'
  5.     var n_data = {
  6.         header: header, //widget’s name
  7.                 text:'<p>'+text+'</p>',//error notification text
  8.                 date: date_now //date
  9.             },
  10.         callbacks = { done: function(){console.log('done');}, //successfully added and saved AJAX done
  11.         fail: function(){console.log('fail');}, //AJAX fail
  12.         always: function(){console.log('always');} //it always requests
  13.     };
  14.     errors.add_error(n_data,callbacks);
  15. AMOCRM.notifications.show_message_error(n_data, callbacks); //Manual request of your notification error.

Adding calls to the Incoming leads

In amoCRM, there is the «Incoming lead» entity, that receives all leads from various integrations, including VoIP.

Incoming calls from unknown numbers (there is no linked contact in the system) that are received by the user, will appear in the "Incoming leads" column. The user can not manually move a request to "Incoming leads".

For widgets that work with SIP: the request will disappear from «Incoming leads» if the user creates a contact or a company with this phone number. The request is a brief information about the call: the caller’s phone number, the time of the call, the duration of the call. You can listen to the call or download it.

The user can add a note or plan a to-do in the call result modal window, and they will be linked to the lead if the "Incoming lead" is accepted. When you drag an incoming lead and drop it in one of the pipeline’s lead stages, a lead and a contact (with the caller’s phone number) are automatically created. The name of the lead will look like "Call from and a phone number", the name of the contact will look like "Autocontact phone number". If the request is declined, it will disappear from the "Incoming leads", the information about the call will disappear as well.

Example of adding calls to the "Incoming leads"

Incoming leads adding method.

Method URL
POST /api/v2/incoming_leads/sip

Parameters

Parameter Type Description
add/source_name
require
string Lead source’s name
add/source_uid
require
string Lead’s unique identifier
add/pipeline_id int Digital Pipeline’s id, if this parameter is not sent then the lead will be added to the “Incoming Leads” of the first pipeline
add/created_at timestamp The date and the time of incoming lead creation
add/incoming_lead_info array An array that contains an incoming lead data
add/incoming_entities
require
array An array that contains created entities elements data. It’s required because when an incoming lead is accepted, the corresponding element of the entity will be created.
add/incoming_entities/leads array An array that contains the data for creating a new lead. It may contain all parameters and custom fields that are available to “Leads” in the account.
add/incoming_entities/contacts array An array that contains the data for creating a new contact. It may contain all parameters and custom fields that are available to “Contacts” in the account.
add/incoming_entities/companies array An array that contains the data for creating a new company. It may contain all parameters and custom fields that are available to “Companies” in the account.
add/incoming_lead_info/to
require
int A user’s identifier who accepted the call
add/incoming_lead_info/from
require
string External phone number
add/incoming_lead_info/date_call
require
timestamp The date and the time of the call
add/incoming_lead_info/duration
require
int Call duration
add/incoming_lead_info/link
require
string Call recording link
add/incoming_lead_info/service_code
require
string The code of the widget or the service through which the call was made
add/incoming_lead_info/uniq
require
string Unique call code
add/incoming_lead_info/add_note
require
bool Flag, if this parameter is passed, then upon acceptance of the request into the created entities, an event about the made call will be added.

Example

  1. {
  2.    add: [
  3.       {
  4.          source_name: "QSOFT",
  5.          source_uid: "a1fee7c0fc436088e64ba2e8822ba2b3",
  6.          created_at: "1510261200",
  7.          pipeline_id: "41563",
  8.          incoming_entities: {
  9.             leads: [
  10.                {
  11.                   name: "Web design",
  12.                   created_at: "1509483600",
  13.                   status_id: "13667502",
  14.                   responsible_user_id: "504141",
  15.                   price: "83000",
  16.                   tags: "websites, frontend",
  17.                   notes: [
  18.                      {
  19.                         note_type: "7",
  20.                         element_type: "lead",
  21.                         text: "Send a contract’s duplicate"
  22.                      }
  23.                   ],
  24.                   custom_fields: [
  25.                      {
  26.                         id: "4399917",
  27.                         values: [
  28.                            "3692247",
  29.                            "3692248"
  30.                         ]
  31.                      }
  32.                   ]
  33.                }
  34.             ],
  35.             contacts: [
  36.                {
  37.                   name: "Jeff Colbert",
  38.                   custom_fields: [
  39.                      {
  40.                         id: "4396818",
  41.                         values: [
  42.                            {
  43.                               value: "89457898713",
  44.                               enum: "WORK"
  45.                            }
  46.                         ]
  47.                      },
  48.                      {
  49.                         id: "4396819",
  50.                         values: [
  51.                            {
  52.                               value: "email@email.com",
  53.                               enum: "WORK"
  54.                            }
  55.                         ]
  56.                      },
  57.                      {
  58.                         id: "4400115",
  59.                         values: [
  60.                            {
  61.                               value: "1 Market St",
  62.                               subtype: "address_line_1"
  63.                            },
  64.                            {
  65.                               value: "San Francisco",
  66.                               subtype: "city"
  67.                            },
  68.                            {
  69.                               value: "20011",
  70.                               subtype: "zip"
  71.                            },
  72.                            {
  73.                               value: "US",
  74.                               subtype: "country"
  75.                            }
  76.                         ]
  77.                      }
  78.                   ],
  79.                   responsible_user_id: "504141",
  80.                   date_create: "1509483600"
  81.                }
  82.             ],
  83.             companies: [
  84.                {
  85.                   name: "QSOFT"
  86.                }
  87.             ]
  88.          },
  89.          incoming_lead_info: {
  90.             to: "41565",
  91.             from: "+19456153101",
  92.             date_call: "1509483600",
  93.             duration: "54",
  94.             link: https://www.example.com/records/2017/11/01/98431.mp3,
  95.             service_code: "CkKwPam6",
  96.             uniq: "a1fee7c0fc436088e64ba2e8822ba2b3ewrw",
  97.             add_note: "Agreed to cooperate"
  98.          }
  99.       }
  100.    ]
  101. }

Call list

You can create call lists from lists of contacts, companies and leads. To do this, you should specify the elements of the list that you want to add, and by clicking on the "more" tab, you can add the selected items to your call list.

You can implement automatic calling with the time interval specified in the widget settings. In the composed call list you can pause an auto-calling or skip one of the list items and move on to the next one.

We give some key features of the composing of the call list in the example. You can check out a complete and exhaustive example of the call list implementation in the example of a full-featured VoIP widget here.

Example of selecting items

Call list example

In order to compose a call list, first, you need to implement the function of selecting items from the entities list. An example of implementing the selection of items for the script.js structure of your widget.

Example

  1. this.callbacks = {
  2. contacts: { //Choose entities elements from lists of contacts or companies
  3.         selected: function () {
  4.           var data = self.list_selected()['selected'],
  5.             nothing_added = true;
  6.           $.each(data, function (k, v) {
  7.             (function (v) {
  8.               var call_element = {},
  9.                 list_model = AMOCRM.data.current_list.where({id: v.id}),
  10.                 company;
  11.               list_model = list_model[0] || {};
  12. /* Receive a data from each selected element */
  13.               call_element.element_id = v.id;
  14.               call_element.element_type = list_model.get('element_type');
  15.               call_element.type = list_model.get('element_type');
  16.               call_element.phone = v.phones[0] || false;
  17. /* Companies list scope is the same as contacts scope— clist. In this regard, we need to
  18. additionally
  19. clarify an entity that selected elements are related */
  20.               call_element.entity = call_element.element_type == 1 ? 'contact' : 'company';
  21.               call_element.element = {};
  22.               call_element.element.text = list_model.get('name')['text'];
  23.               call_element.element.url = list_model.get('name')['url'];
  24.               company = list_model.get('company_name') || false;
  25.               if (company) {
  26.                 call_element.company = {};
  27.                 call_element.company.text = company.name;
  28.                 call_element.company.url = company.url;
  29.               }
  30.               if (call_element.phone) {
  31.                 self.__CallsList.addCall(call_element);   //Pass selected elements to your processing function, addCall is not a finished SDK method , it’s given as an example
  32.                 nothing_added = false;
  33.                 $(document).trigger('list:cookies:update');
  34.               } else if (nothing_added && k == data.length - 1) {
  35.                 self.notifers.show_message_error({
  36.                   text: self.i18n('caller').nothing_to_add,
  37.                   without_header: true
  38.                 });
  39.               }
  40.             })(v);
  41.           });
  42.         }
  43.       },
  44.       leads: {  //Choose elements from  leads list
  45.         selected: function () {
  46.           var data = self.list_selected()['selected'];
  47.           (function (data) {
  48.             self.tools.request({
  49.                 selected: data
  50.               },
  51.               'get_contacts_by_leads',
  52.               function (data) {
  53.  
  54.                 data.contacts = data.contacts || [];
  55.                 if (data.contacts.length <= 0) {
  56.                   self.notifers.show_message_error({
  57.                     text: self.i18n('caller').nothing_to_add,
  58.                     without_header: true
  59.                   });
  60.                   return;
  61.                 }
  62.                 $.each(data.contacts, function (k, v) {
  63.                   (function (v) {
  64.                     var call_element = {},
  65.                       company = false,
  66.                       list_model = AMOCRM.data.current_list.where({id: v.id});
  67.                     list_model = list_model[0] || {};
  68.  
  69.                     call_element.element_id = v.element_id;
  70.                     call_element.element_type = v.element_type;
  71.                     call_element.type = v.element_type;
  72.                     call_element.phone = v.phone || false;
  73.                     call_element.entity = v.entity;
  74.                     call_element.element = v.element;
  75.                     company = v.company || false;
  76.                     if (typeof company == 'object') {
  77.                       call_element.company = {};
  78.                       call_element.company.text = company.text;
  79.                       call_element.company.url = company.url;
  80.                     }
  81.                     if (call_element.phone) {
  82.                       self.__CallsList.addCall(call_element); //Pass selected elements to your processing function, addCall is not a finished SDK method, it’s given as an example
  83.                       $(document).trigger('list:cookies:update');
  84.                     }
  85.                   })(v);
  86.                 });
  87.               }
  88.             );
  89.           })(data);
  90.         }
  91.       }
  92. };

Since we recommend setting the “everywhere” scope for all VoIP widgets in manifest.json, there is no need to specify additional scopes to select items from the list.

Next, we need to put the selected items in a list view. In the example, there is a render of a *.twig format template, with the structure of the template itself.

Example

  1. render: function (calls) {
  2.         var _this = this;
  3.         _this.widget.getTemplate( //Choose a call_list template
  4.           'call_list',
  5.           {},
  6.           function (template, base_params) {
  7.             _this.$el.html(template.render(_.extend(base_params, {
  8.               list_expanded: 0,
  9.               open_contact: !(cookie.get(_this.widget.params.widget_code + '_open_contact') == '0'),
  10.               lang: _this.lang
  11.             })));
  12.             _this.$el.find('#sortable_calls_list').sortable({ //calls sorting
  13.               items: 'div.amo__vox__implant_call__list_wrapper__list__task',
  14.               handle: '.icon-sortable',
  15.               axis: 'y',
  16.               containment: '#vox_imp__call_list_wrapper .amo__vox__implant_call__list_wrapper__list',
  17.               scroll: false,
  18.               tolerance: 'pointer',
  19.               stop: function () {
  20.                 _this.startSort();
  21.               }
  22.             });
  23.             calls = calls || [];
  24.             if (calls.length > 0) {
  25.               _this.calls.push(calls);  //Add to your array for calling, calls is not a finished SDK method, it’s given as an example
  26.             }
  27.           }
  28.         );
  29.         return this;
  30.       }

Example of a *.twig template for the call list.

  1. <div id="vox_imp__call_list_wrapper" class="{{ widget_code }}_call__list_wrapper{% if list_expanded %} expanded{% endif %}
  2. {{ widget_code
  3. }}">
  4.   <div class="{{ widget_code }}_call__list_wrapper__header">
  5.     <span id="clear_call_list" class="{{ widget_code }}_call__list_wrapper__header_icon icon-clear"
  6.           title="{{ lang.clear }}"></span>
  7.  
  8.     <div class="{{ widget_code }}_call__list_wrapper__header_additional_option">
  9.       <span id="clear_call_list" class="{{ widget_code }}_call__list_wrapper__header_clear">{{ lang.clear }}</span>
  10.     </div>
  11.     <span class="{{ widget_code }}_call__list_wrapper__header_name">{{ lang.call_list }}:</span>
  12.  
  13.     <div class="{{ widget_code }}_call__list_wrapper__header__switcher">
  14.       <span class="{{ widget_code }}_call__list_wrapper__header__switcher_text">{{ lang.open_contact_w_calling }}</span>
  15.  
  16.       <div class="switcher_wrapper">
  17.         <label for="call_list_switcher"
  18.                class="switcher call_list_switcher switcher__{% if open_contact == 1 %}on{% else %}off{% endif %}"
  19.                id=""></label>
  20.         <input type="checkbox" value="Y" name="call_list_switcher" id="call_list_switcher" class="switcher__checkbox">
  21.       </div>
  22.     </div>
  23.   </div>
  24.   <div class="{{ widget_code }}_call__list_wrapper__hint">{{ lang.empty_calls_list }}</div>
  25.   <div class="{{ widget_code }}_call__list_wrapper__list custom-scroll" id="sortable_calls_list"></div>
  26. </div>
  27. <div class="{{ widget_code }}_call__footer {{ widget_code }}">
  28.   <div id="vox_imp__call_list_btn" class="{{ widget_code }}_call__btn {{ widget_code }}_call__list_btn"
  29.        title="{{ lang.call_list }}">
  30.     <span class="nav__notifications__counter call_list_notifications"></span>
  31.   </div>
  32.   <div class="{{ widget_code }}_call__status">
  33.     <div class="{{ widget_code }}_call__status__contact"></div>
  34.     <div class="{{ widget_code }}_call__status__talk">
  35.       <span class="{{ widget_code }}_call__status__talk__time"></span>
  36.             <span id="vox_implant__icon_wrapper" class="{{ widget_code }}__icon_wrapper">
  37.                 <span id="vox_imp__rec_call" class="{{ widget_code }}_call__status__talk__rec rec_is_on"
  38.                       title="{{ lang.talk_recording }}"></span>
  39.                 <span id="vox_imp__play_call" class="{{ widget_code }}_call__status__queue_pause"
  40.                       title="{{ lang.pause }}"></span>
  41.             </span>
  42.     </div>
  43.   </div>
  44.   <div class="{{ widget_code }}_call_options">
  45.     <div id="vox_imp__mic_btn" class="{{ widget_code }}_call__btn {{ widget_code }}_call__mute_mic_btn mute_is_on"
  46.          title="{{ lang.mute_speaker }}"></div>
  47.     <div class="{{ widget_code }}_call__btn {{ widget_code }}_call__skip_btn" title="{{ lang.skip }}"></div>
  48.     <div id="vox_imp__dial_btn" class="{{ widget_code }}_call__btn {{ widget_code }}_call__dial_btn"
  49.          title="{{ lang.dialling }}"></div>
  50.     <div id="vox_imp__hung_up_btn" class="{{ widget_code }}_call__btn {{ widget_code }}_call__phone_btn js-hungup_call">
  51. </div>
  52.   </div>
  53. </div>

Built-in call feature (WebRTC)

WebRTC is a technology that provides you to make and receive calls right in your browser. Please note that not all browsers or not all browsers versions support this technology. You can find more information about the currently supported browsers on the official technology page.

WebRTC is an open source solution, and some widgets use it for integrating amoCRM with virtual PBXs.

The displaying of the working feature of making calls looks different in different browsers. In Mozilla Firefox, this is the microphone icon. In the Google Chrome browser, the active feature is displayed as a red sign on the tab and the camera icon on the right side of the address bar that confirms an access to your microphone.

Example of a built-in call

Example of implementing WebRTC into amoCRM.

Example

  1. initYourWidget: function () {
  2.     $.getScript('///*link*//your_script.min.js', _.bind(function () {
  3.  
  4.     /* Your VoIP script processing*/
  5.  
  6.     }, this));
  7.  
  8.   initialize: function (params) {
  9.   AMOCRM.widgets.notificationsPhone({
  10.               ns: this.widget.ns,
  11.              click: _.bind(function () {
  12.                   this.$el.toggle();  //Displaying a WebRTC interface window
  13.               }, this)
  14.     });
  15. }