CRM Routing allows routing to a specific Queue or IVR, and it also allows playing sound files based on the information fetched from CRM. When the call comes in AGI, PBXware will first contact the CRM and make a specific action based on the returned value.
To set up the configuration in PBXware, navigate to the CRM section with the 'Integration' and 'Routing' sub-menus. When on the 'Routing' section, a user can set up rules based on which calls will be routed. On DID and IVR, new destinations can be assigned the rule which will be evaluated for a particular DID/IVR.
NOTE: CRM Routing must be enabled in a license.
For testing purposes I will explain how it works with Zoho CRM which is set up under CRM -> Integration tab.
Below is the screenshot from the Integration tab, which is showing that Integration with ZOHO is successful, which is pre-required in this case.
Let’s navigate now to the Routing tab and add the Routing rule. We will need to populate the following fields:
Rule name - this name is defined by the user
CRM Field Name - CRM field-defining which value should be fetched
The field above needs to be populated with a suitable API name from the CRM side.
NOTE: Please note that this field needs to be populated with a suitable API Name.
For more on how to find the API Name, please refer to the example of Zoho CRM below. This is applied to every supported CRM respectively.
For instance, this is a link of the Zoho CRM account:
https://crm.zoho.com/crm/orgXXXXXXXX/settings/api/modules
Once users are logged in to their CRM account, they can navigate to 'Settings' -> 'API' and find the applicable API Name. Please refer to the screenshots.
When we open the page, we will get the list of API names of all the modules, fields, and related lists that can be used in third-party integrations.
Upon clicking on Accounts for example, we will get a list of api names for Accounts. For example, we will use Account_Name in this case as CRM Field Name:
NOTE: Please note that the link provided above refers to Zoho CRM so the page URL can have one of three possible formats: https://crm.zoho.com/crm/, https://crm.zoho.eu/crm/, or https://crm.zoho.in/crm/ depending on the Data Center to which a certain Zoho instance belongs to. Therefore, the format has to be changed accordingly. Also, the 'orgXXXXXXXX' stands for the organization number to which users can have access once they are logged in to their CRM account.
Next, in CRM settings section, we will populate the required fields.
CRM To Use:
Select one of two options to use:
1. CRM from CRM > Integration: PBXware will contact CRM and fetch the value.
2. Custom CRM: A customer should implement communication with CRM on his own.
If 'CRM To Use' is set to CRM from CRM > Integration, the following options are available:
CRM Modules:
Define from which CRM module PBXware should fetch information
(E.g. Accounts/Contacts/Leads)
CRM Username:
Enter a valid CRM username
(E.g. Example CRM Username)
CRM Password:
Enter the CRM password in the same way as for gloCOM. Please follow the instructions for a specific CRM.
In my case I have chosen to use Account _Name as CRM Field Name, this API field is available under Accounts and Contacts fields on ZOHO side, it is not available in Leads, so in order to setup correctly routing rule, I have chosen Accounts under CRM Modules field. If Leads would be chosen as one of the CRM Modules, CRM Routing Rule would not be successfully applied as PBXware would try to fetch the value from this field under the Lead module and it does not exist on the CRM side.
We will also need to populate the Default destination field which will be used to redirect the calls in case the return value does not match any rules.
Rules:
These fields are the most important for CRM routing, as they define where calls will be routed to. Each rule needs to be fulfilled in order for PBXware to route it to a defined destination. If the rule is not fulfilled, the call will be routed to the Default destination that is set above.
For example, in my case I have account on ZOHO side added like this:
The account name in this case is testrouting1. So, I will add the rule like this:
So, when the call comes from the number which has in Account_Name testrouting1, the call should be sent to IVR 104.
How Does Routing Work?
After fetching the value from CRM, PBXware goes through the rules row by row and evaluates the comparison between the returned value and a value from the rule’s row by using the arithmetic operator defined in the row. A destination for a caller is the destination from the first row which matches the criteria.
For example, a user needs to filter inbound calls on DID and send calls to destinations based on some fields in his/her CRM. Following this, in CRM, there is a "status" field name with the customer's status and the value of the field that can be 'GOLD', 'SILVER', 'BRONZE', and so on. A user can set his/her CRM routing rule to check if the customer is marked as 'GOLD'. If this is true, a user can send the call to the appropriate location such as IVR, Queue, and so on.
Test cases:
The call from the number which matches the rules
Let’s test it now on my test tenant. I will make test call from the number 1202888888 to DID which I have pointed to CRM routing, as shown on the screenshot below:
When I made first test call, I could see in the CLIR this:
No limit for crm_routing 200 result=1
get variable CALLEDNUMBER 200 result=1 (1202888888)
get variable CALLERID(num) 200 result=1 (1202888888)
21:55:57 This is local extension, skipping Time Based Dialing/miniLCR ... 200 result=1
Set limit - 8 200 result=1
Limit not exceeded (1 < 8) for auto_attendants 200 result=1
exec Set CDR(userfield)=104 200 result=0
get variable CALLEDNUMBER 200 result=1 (1202888888)
get variable DIDNUMBER 200 result=1 (1202777777)
exec Answer
And my call went to IVR 104, as set in routing rules. To check this further, we can also monitor CRM log, which can be checked with command:
tail -f /opt/pbxware/pw/var/log/crmiservice/crmiservice.log
And we can see:
2025-04-16 21:55:56 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 21:55:56 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))"
2025-04-16 21:55:57 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 21:55:57 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000489099","Account_Name":"testrouting1"}]
This is the case when caching is disabled. It will work the same when caching is enabled (at least for ZOHO) and in the log you will see:
2025-04-16 22:22:52 - DEBUG --> CrmCache - Searching for customer by number: 1202888888
2025-04-16 22:22:52 - DEBUG --> CrmCache - No customer found with number: 1202888888
2025-04-16 22:22:52 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:22:52 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))"
2025-04-16 22:22:53 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:22:53 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000489099","Account_Name":"testrouting1"}]
The call from the number which does not match the rules defined
Let’s make a call from the number which belongs to a different Account and see what will happen.
For example, in the Accounts page on ZOHO, I have a number which belongs to Account name testrouting2.
Let’s see what will happen now. When the call came to PBXware from this number, the call was sent to default destination as the rule was not fulfilled.
In CLIR in this case I could see this:
No limit for crm_routing 200 result=1
get variable CALLEDNUMBER 200 result=1 (1202666666)
22:11:10 get variable CALLERID(num) 200 result=1 (1202666666)
No valid rule for returned value ... 200 result=1
Fetched value is empty or not set, checking default destination ... 200 result=1
exec ForkCDR re 200 result=0
set extension 102 200 result=0
exec Set CDR(userfield)=102 200 result=0
set variable CDR(odbctable) pbxware_400.cdr 200 result=1
set variable CDR(tenant) 400 200 result=1
Starting 'Special Routes' detection ... 200 result=1
No 'Special Routes' detected ... 200 result=1
Detecting destination for '102' ... 200 result=1
And in the log:
2025-04-16 22:11:10 - DEBUG --> CrmCache - Searching for customer by number: 1202666666
2025-04-16 22:11:10 - DEBUG --> CrmCache - No customer found with number: 1202666666
2025-04-16 22:11:10 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:11:10 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202666666)OR(Phone:equals:120-266-6666)OR(Phone:equals:120%20266%206666))"
2025-04-16 22:11:10 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202666666)OR(Phone:equals:120-266-6666)OR(Phone:equals:120%20266%206666))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:11:10 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000489175","Account_Name":"testrouting2"}]
The call from the number which is added under Leads and does not exist in Accounts
I will make the call now from the number which does not exist under Accounts. It has been added under Leads. Remember, Leads has not been added under CRM Modules and also there is no Account_Name API name for Leads modules.
In this case, the call will be sent again to default destination and in the log we can see:
2025-04-16 22:17:38 - DEBUG --> CrmCache - Searching for customer by number: 1202111111
2025-04-16 22:17:38 - DEBUG --> CrmCache - No customer found with number: 1202111111
2025-04-16 22:17:38 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:17:38 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111))"
2025-04-16 22:17:39 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:17:39 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts
2025-04-16 22:17:39 - DEBUG --> ZohoConnector - createCustomerPageUrl returns:https://crm.zoho.eu/crm/org20105630807/tab/Accounts/829914000000506001/
2025-04-16 22:17:39 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000506001","webpage":"https:\/\/crm.zoho.eu\/crm\/org20105630807\/tab\/Accounts\/829914000000506001\/","name":"Unknown","workphone":"1202111111","mobilephone":null,"homephone":null,"fax":null,"email":null,"company":null,"type":"Accounts","calllogid":null,"calllogurl":null}]
CLIR will show again:
No limit for crm_routing 200 result=1
get variable CALLEDNUMBER 200 result=1 (1202111111)
get variable CALLERID(num) 200 result=1 (1202111111)
22:17:39 Fetched value is empty or not set, checking default destination ... 200 result=1
exec ForkCDR re 200 result=0
set extension 102 200 result=0
exec Set CDR(userfield)=102 200 result=0
set variable CDR(odbctable) pbxware_400.cdr 200 result=1
set variable CDR(tenant) 400 200 result=1
Starting 'Special Routes' detection ... 200 result=1
No 'Special Routes' detected ... 200 result=1
Detecting destination for '102' ... 200 result=1
Found Destination localextensions (range 102 - 102) 200 result=1
The call from the number which does not exist on CRM side
In this case, the call will be also sent to the default destination and in crm.log we would see this:
2025-04-16 22:21:43 - DEBUG --> CrmCache - Searching for customer by number: 120222222
2025-04-16 22:21:43 - DEBUG --> CrmCache - No customer found with number: 120222222
2025-04-16 22:21:43 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:21:43 - VARS --> string(57) "Lookup Query: /search?criteria=((Phone:equals:120222222))"
2025-04-16 22:21:43 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:120222222))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:21:43 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts
2025-04-16 22:21:43 - DEBUG --> ZohoConnector - createCustomerPageUrl returns:https://crm.zoho.eu/crm/org20105630807/tab/Accounts/829914000000507001/
2025-04-16 22:21:43 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000507001","webpage":"https:\/\/crm.zoho.eu\/crm\/org20105630807\/tab\/Accounts\/829914000000507001\/","name":"Unknown","workphone":"120222222","mobilephone":null,"homephone":null,"fax":null,"email":null,"company":null,"type":"Accounts","calllogid":null,"calllogurl":null}]
Examples when multiple CRM Modules are selected
I have edited now my CRM rules and added it like this:
When the call comes from the number which fulfills rules criteria, the log would look like this:
2025-04-16 22:25:29 - DEBUG --> CrmCache - Searching for customer by number: 1202888888
2025-04-16 22:25:29 - DEBUG --> CrmCache - No customer found with number: 1202888888
2025-04-16 22:25:29 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:25:29 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))"
2025-04-16 22:25:29 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:25:29 - INFO --> ZohoConnector - Search Contacts for CRM Routing
2025-04-16 22:25:29 - VARS --> string(316) "Lookup Query: /search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888)OR(Home_Phone:equals:1202888888)OR(Home_Phone:equals:120-288-8888)OR(Home_Phone:equals:120%20288%208888)OR(Mobile:equals:1202888888)OR(Mobile:equals:120-288-8888)OR(Mobile:equals:120%20288%208888))"
2025-04-16 22:25:29 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Contacts/search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888)OR(Home_Phone:equals:1202888888)OR(Home_Phone:equals:120-288-8888)OR(Home_Phone:equals:120%20288%208888)OR(Mobile:equals:1202888888)OR(Mobile:equals:120-288-8888)OR(Mobile:equals:120%20288%208888))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:25:29 - INFO --> ZohoConnector - Search Leads for CRM Routing
2025-04-16 22:25:29 - VARS --> string(212) "Lookup Query: /search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888)OR(Mobile:equals:1202888888)OR(Mobile:equals:120-288-8888)OR(Mobile:equals:120%20288%208888))"
2025-04-16 22:25:30 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Leads/search?criteria=((Phone:equals:1202888888)OR(Phone:equals:120-288-8888)OR(Phone:equals:120%20288%208888)OR(Mobile:equals:1202888888)OR(Mobile:equals:120-288-8888)OR(Mobile:equals:120%20288%208888))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:25:30 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000489099","Account_Name":"testrouting1"}]
We can see here that it is searching for the Account_Name field in Accounts, Leads and Contacts.
If we make a call from the number which is is added under Leads, which does not contain Account_Name api name, the call will went to the default destination:
2025-04-16 22:37:49 - DEBUG --> CrmCache - Searching for customer by number: 1202111111
2025-04-16 22:37:49 - DEBUG --> CrmCache - No customer found with number: 1202111111
2025-04-16 22:37:49 - INFO --> ZohoConnector - Search Accounts for CRM Routing
2025-04-16 22:37:49 - VARS --> string(120) "Lookup Query: /search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111))"
2025-04-16 22:37:49 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts/search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:37:49 - INFO --> ZohoConnector - Search Contacts for CRM Routing
2025-04-16 22:37:49 - VARS --> string(316) "Lookup Query: /search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Home_Phone:equals:1202111111)OR(Home_Phone:equals:120-211-1111)OR(Home_Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))"
2025-04-16 22:37:49 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Contacts/search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Home_Phone:equals:1202111111)OR(Home_Phone:equals:120-211-1111)OR(Home_Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:37:49 - INFO --> ZohoConnector - Search Leads for CRM Routing
2025-04-16 22:37:49 - VARS --> string(212) "Lookup Query: /search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))"
2025-04-16 22:37:49 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Leads/search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:37:49 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000506001","Account_Name":"Unknown"}]
Example when incorrect module is selected
In my case I will select the Leads module now and leave Account_Name as the CRM Field name. NOTE: This fied name does not exist in Leads on ZOHO.
In this case, every call will go to default destination, as the rule cannot be fulfilled. In the crm.log we would see:
2025-04-16 22:42:56 - DEBUG --> CrmCache - Searching for customer by number: 1202111111
2025-04-16 22:42:56 - DEBUG --> CrmCache - No customer found with number: 1202111111
2025-04-16 22:42:56 - INFO --> ZohoConnector - Search Leads for CRM Routing
2025-04-16 22:42:56 - VARS --> string(212) "Lookup Query: /search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))"
2025-04-16 22:42:56 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Leads/search?criteria=((Phone:equals:1202111111)OR(Phone:equals:120-211-1111)OR(Phone:equals:120%20211%201111)OR(Mobile:equals:1202111111)OR(Mobile:equals:120-211-1111)OR(Mobile:equals:120%20211%201111))&page=1&per_page=200&fields=id,Account_Name
2025-04-16 22:42:57 - DEBUG --> ZohoConnector - https://www.zohoapis.eu/crm/v2/Accounts
2025-04-16 22:42:57 - DEBUG --> ZohoConnector - createCustomerPageUrl returns:https://crm.zoho.eu/crm/org20105630807/tab/Accounts/829914000000508001/
2025-04-16 22:42:57 - DEBUG --> Route - GET /customers/search returns: [{"id":"829914000000508001","webpage":"https:\/\/crm.zoho.eu\/crm\/org20105630807\/tab\/Accounts\/829914000000508001\/","name":"Unknown","workphone":"1202111111","mobilephone":null,"homephone":null,"fax":null,"email":null,"company":null,"type":"Accounts","calllogid":null,"calllogurl":null}]
Custom CRM
In case of a custom CRM (CRM implemented by a customer), a URL which PBXware will try to reach is as follows:
CRM URL
{URL}?field_name={CRM_FIELD_NAME}&dtmf={DTMF}
URL = CRM URL set on the Routing Rule,
CRM_FIELD_NAME = CRM Field Name set on the Routing Rule,
DTMF = DTMF entered by a caller (available only for IVRs when the 'Greeting instructions' option is selected).
Based on the configuration from the example a URL will be:
https://crmurl.com?field_name=Field_Name
HTTP Method POST
PBXware will only send a POST request if the user specifically sets the option to "Yes." When a POST request is sent, PBXware includes the data in the request body as JSON, with the Content-Type header set to application/json.
Custom HTTP Header
Users can specify any valid HTTP header value to include in the HTTP request sent by PBXware.
NOTE: A user who implements the Custom CRM integration is the one who is in charge of handling this request on his/her side.