3CX PBX in the Cloud
1 year FREE - no ties!
google cloud platform
3CX
Zero Admin
With the new Dashboard
3CX
Bulletproof Security
With SSL certs and NGINX
3CX
Install on $200 Appliance
Intel MiniPC architecture
3CX
New, Intuitive Windows Client
More themes, more UC
3CX
More CRM Integrations
Scripting Interface to add your own
3CX
Improved Integrated Web Conferencing
iOS and Android apps included
3CX
Run On-Premise or in the Cloud
Google, OVH, Windows & Linux
Fast & easy call management
With the 3CX Web Client

Server Side CRM Template XML description

CRM template XML description

On this topic

CRM template XML description

Introduction

The XML template format

Number element

Connection element

Parameters element

Authentication element

No Authentication

Basic Authentication

Scenario Authentication

Scenarios element

Request element

Rules element

Example

Variables element

Variables filtering

Outputs element

Output for each type of scenario

Phone Number Matching Scenario

Authentication Scenario

OAuth Response Scenario

Chained scenario

Expressions

Variables

Predefined variables

String concatenation

Method invocation

Condition evaluation

Debugging

Introduction

In this document we will describe the format of the XML template used for the CRM integration, and also provide a description of how the engine executes according to the settings defined in the template. Finally, we’ll explain how we can easily debug a template.

The XML template format

The root element of the XML template file is <Crm>. This element has the following attributes:

Country (String) - Name of the country of the CRM. Not in use at the moment

Name (String) - Name of the template. It is shown to the user to identify the CRM.

Version (integer) - Template version for updates

The <Crm> element has the following children elements:

  • <Number>
  • <Connection>
  • <Parameters>
  • <Authentication>
  • <Scenarios>

Number element

This element is used to format the received caller number in the way that the CRM expects it. The resulting number will be used for contact matching. It has the following attributes:

Prefix (Enum) - describes what to do with the caller number prefix:

  • AsIs - do not modify prefix: +,00 ⇒ +,00
  • Off - exclude prefix: +,00 ⇒ X
  • Plus - use ‘plus’ sign: +,00 ⇒ +
  • Zeros - use zeros as prefix: +,00 ⇒ 00

MaxLength (Number expression) - Maximum number of digits to keep in the phone number.

For example, if MaxLength=6, the phone number will be converted taking only the last 6 digits:
+123456789 ⇒ 456789.
If the expression is empty, the number is not changed.

Example:

<Number Prefix="Zeros" MaxLength="[MaxLength]"/>

Connection element

This element describes connection-specific options for the CRM. It has the following attributes:

MaxConcurrentRequests (integer) - Specifies how many simultaneous requests can be sent to the CRM. A request is considered a number lookup for a single call. Please note that many queries for the same call (different scenarios to query for example for contacts, leads or accounts), are counted as one.

Example:

<Connection MaxConcurrentRequests="2"/>

Parameters element

This element contains a collection of children <Parameter> elements, which are variables that can be configured by the user from the 3CX Management Console. Each child <Parameter> element has the following attributes:

  • Name (string) Name of the parameter. The parameter value can be obtained providing its name in square brackets. For example: [SomeParameter]
  • Type (enum) The type of the parameter. There are two types available at the moment: String - represents a string. OAuth - represents a button to trigger the OAuth authentication flow.
  • Title (string) Caption to show in the 3CX Management Console for this parameter.
  • Validation (enum) The validation rule to apply to this parameter when entered in the 3CX Management Console. No validation is applied if the attribute is missing. Possible values are: ip_address, port, subnet_mask, email
  • Default (string) The default value for the parameter.
  • RequestUrl (String Expression) The URL that needs to be opened to start the OAuth authentication flow, only valid when the parameter type is OAuth.
  • ResponseScenario (string) - The ID of the scenario that should be executed to get the refresh token returned by the OAuth server, only valid when the parameter type is OAuth.

Example:

<Parameters>

    <Parameter Name="Domain" Type="String" Title="Domain:"/>

    <Parameter Name="ResponseDomain" Type="String" Title="Response Domain:"/>

    <Parameter Name="RefreshToken" Type="OAuth" Title="Authentication:" RequestUrl="[Domain]/api/oauth2/auth?client_id=[ClientID]&amp;redirect_uri=[ResponseDomain][_oAuthResp]&amp;response_type=code&amp;force_login=0" ResponseScenario="OAuthCodeProcessing"/>

</Parameters>

Authentication element

This element defines the authentication method used by the CRM. There are three options at the moment:

  • No authentication: Type="No"
  • Basic authentication: Type="Basic"
  • Scenario authentication: Type="Scenario"

No Authentication

This option is used when there is no authentication, or the CRM uses a custom authentication mechanism, for example some parameters in the query string. But no Authentication headers are needed in the requests sent to the CRM.

Basic Authentication

In this case every HTTP request sent to the CRM will include the Authorization header, encoded according to the basic authentication protocol, using the value taken from the <Value> child element.

Example:

<Authentication Type="Basic">

    <Value>[CompanyName]+[PublicKey]:[PrivateKey]</Value>

</Authentication>

Scenario Authentication

With this type of authentication it is possible to describe complex authentication scenarios, including OAuth. The idea is to invoke a scenario to get the header value that we need to use for requests (for example, OAuth access token), the token expiration, etc. using specific requests to the CRM.

The authentication scenario is identified by its Id, which should match to the Value of the Authentication element.

Example:

<Authentication Type="Scenario">

    <Value>OAuthAccessToken</Value>

</Authentication>

<Scenarios>

    <Scenario Id="OAuthAccessToken">

    …

Scenarios element

This element describes the different scenarios that will be used when interacting with the CRM. For example, a scenario might describe an authentication flow, another scenario might describe how to query for contacts, etc. This element contains a collection of children <Scenario> elements.

A Scenario is the main unit of data processing, and works as follows:

  1. It performs an HTTP request to the CRM.
  2. It splits and filters the results according to rules and the response data (JSON or XML).
  3. For each result:
  1. It fills variables taken from the response data.
  2. It provides an output or calls an inner scenario recursively by id.

The Scenario element has the following attributes:

Id (String) Unique identifier of each scenario or an empty string. When the Id is set, the value is used to identify the scenario for further processing. For example, to invoke it for authentication, to invoke it as a child scenario, etc. Empty value are used when the scenario is created for caller number matching.

The Scenario element has the following children elements:

  • <Request>
  • <Rules>
  • <Variables>
  • <Outputs>

Request element

This child element is mandatory, as each scenario must perform an HTTP request to start off. The Request element has the following attributes:

  • Url (String Expression) - URL to invoke when the scenario is executed.
  • RequestType (enum) The HTTP request method: Get - for GET requests. Post - for POST requests.
  • Message (String Expression) - The text to use as HTTP Content for the POST request.
    Not applicable for Get requests. Optionally this can be set using a child <PostValues> element as explained below. Please note that this attribute should not be set if the <PostValues> child element is defined..
  • ResponseType (enum) - The type of response expected. Valid values are: Json, Xml
  • SkipIf (Boolean Expression) - If the expression evaluates to true, then the request is skipped. This means that all variables for this scenario will be set to empty, and the output will be provided only if its AllowEmpty attribute is set to true

When the RequestType is Post, a collection of key-value pairs can be defined as children elements. In this case, the request will look as follows:

<Request Url="https://login.salesforce.com/services/oauth2/token" RequestType="Post" ResponseType="Json">
 <PostValues>
   <Value Key="grant_type">password</Value>
   <Value Key="client_id">[ClientId]</Value>
   <Value Key="client_secret">[ClientSecret]</Value>
   <Value Key="username">[UserName]</Value>
   <Value Key="password">[Password][SecurityToken]</Value>
 </PostValues>
</Request>

Rules element

This element is used to analyze the response returned by the server. The response can be JSON or XML, and is automatically converted to a tree-view structure. Each node of the structure can be one of 3 types:

  1. An array of elements: unnamed set of similar elements.
  2. An element with named properties.
  3. The value itself: when the node is a leaf of the tree, it is a value of an elementary type

We need to perform 2 tasks when processing this response tree:

  1. Identify the root element for each contact returned by the server.
  2. Optionally filter the contacts that we need.

A scenario might have one or more children <Rules> elements. Also, each <Rules> element can have one or more children <Rule> elements. The returned data (JSON or XML) is processed according to these rules, and each record will pass the filter if:

  • At least one <Rule> element from a <Rules> element passes the filter (<Rule> elements are evaluated with an OR condition).
  • AND every <Rules> element passes the filter, according to the previous bullet point (<Rules> elements are evaluated with an AND condition).

The value inside the child <Rule> element is the path to the matching element in the response data tree, and the attributes of this element are the following:

  • Type (enum) - Matching rule type, which can be one of the following:
  • Any - if the rule is used to determine contact’s root in the response data tree without filtration.
    Number - if the rule should match the data element (provided by the path) to phone number.
  • DestinationEmail - if the rule should match the data element (provided by the path) to the extension number (not in use).
  • Equals - if the rule should match the data element (provided by the path) to the value specified in the attribute Ethalon.
  • Ethalon (String Expression) - Expression to use when Type=Equals. The rule passes if the string representation of Ethalon matches to the data element content.

An example will shed some light on this procedure.

Example

Let's assume that we have the following JSON response returned by the CRM server:

"result": [{

    "id": 10293,

    "firstName": "Johnny",

    "lastName": "Bravo",

    "company": {

        "id": 20,

        "identifier": "PinkNetworksLLC",

        "name": "PinkNetworks, L.L.C."

    },

    "communicationItems": [{

        "id": 10463,

        "type": {

            "id": 2,

            "name": "Direct"

        },

        "value": "123456",

        "defaultFlag": true,

        "communicationType": "Phone"

    },

    {

        "id": 10464,

        "type": {

            "id": 1,

            "name": "Email"

        },

        "value": "mc@3cx.com",

        "defaultFlag": true,

        "communicationType": "Email"

    },

    {

        "id": 10465,

        "type": {

            "id": 4,

            "name": "Cell"

        },

        "value": "987654",

        "defaultFlag": false,

        "communicationType": "Phone"

    }]

},

{

    "id": 18347,

    "firstName": "Hannibal",

    "lastName": "Lecter",

    "company": {

        "id": 23,

        "identifier": "PP",

        "name": "Private psychologist"

    },

    "communicationItems": [{

        "id": 10463,

        "type": {

            "id": 2,

            "name": "Direct"

        },

        "value": "+1123456",

        "defaultFlag": true,

        "communicationType": "Phone"

    }]

}]

The path is an expression to point to a specific node from the response tree. This expression is a string which concatenates node names separated by dots. The path expression points to the value of the selected element, so if the path points to a leaf, the elementary value is returned, and if it points to an array, the array of elements is returned.

In the JSON above:

  • The path “result” points to the array of contacts.
  • The path “result.lastName” points to the 2 leaves with values “Bravo” and “Lecter”.
  • The path “result.communicationItems.type.name” points to the 4 leaves with values: “Direct”, “Email”, “Cell” and “Direct”.

Let’s see how different <Rule> elements work. Consider the following rule:

<Rules>

    <Rule Type="Any">result.firstName</Rule>

</Rules>

This rule will return every record which has a firstName property in the result node. There are 2 records that pass this rule, and therefore will be converted into contacts: one for “Johnny Bravo” and one for “Hannibal Lecter”. If we change the rule as follows:

<Rules>

    <Rule Type="Equals" Ethalon="Hannibal">result.firstName</Rule>

</Rules>

It will return a single record for “Hannibal Lecter”. And if we use the following rule:

<Rules>

    <Rule Type="Any">result.communicationItems.type.name</Rule>

</Rules>

We will get 4 records: 3 of them for “Johnny Bravo” (for direct phone, email and cell phone) and 1 for “Hannibal Lecter” (for direct phone). Then, if we change the rules as follows:

<Rules>

<Rule Type="Equals" Ethalon="Phone">result.communicationItems.communicationType</Rule>

</Rules>

<Rules>

    <Rule Type="Number">result.communicationItems.value</Rule>

</Rules>

The first rule will filter the 3 “Phone” records (direct phone and cell phone for Johnny Bravo, and direct phone for Hannibal Lecter). And the second filter will restrict the result to the numbers that match the caller number. So, for example, if we’re looking for the number “987654”, only one record for “Johnny Bravo” will pass through the filters. And if we’re looking for number “123456” with MaxLength=6, two records will pass through the filters, one for “Johnny Bravo” with number “123456”’ and one for “Hannibal Lecter” with number “+1123456”.

Variables element

After applying the rules to the data returned by the server, we need to fill variables with the parts of the data we need. We can define as many variables as we need.

A scenario can only have one child <Variables> element. And this element might have as many children <Variable> elements as we need. The value inside the child <Variable> element is the path to the matching element in the response data tree, and the attributes of this element are the following:

  • Name (string) - Name of the variable.
  • Path (string) - The path to the matching element in the response data tree. This can also be specified as the element value.

If there are arrays on the path from the root of the tree to the root of the contact, the instance for this specific contact will be selected. But if there are arrays on the path from the root of the contact to the final leaf, and no variable filtering is applied, an exception will be thrown.

Continuing with the JSON response from the example above, let’s assume that we have the following rule to filter the contact root:

<Rules>

    <Rule Type="Any">result.firstName</Rule>

</Rules>

In this case we can easily create variables to get the first name, the last name and the company name:

<Variables>

    <Variable Name="FirstName">result.firstName</Variable>

    <Variable Name="LastName">result.lastName</Variable>

    <Variable Name="CompanyName">result.company.name</Variable>

<Variables>

However, this does not work for phone numbers and email, because that information is stored in arrays, and it’s not possible to define which leaf of the path “result.communicationItems.value” needs to be taken for the email and each phone number type. We need to use variable filtering to disambiguate in this case.

Variables filtering

Each variable can provide a filter to eliminate the ambiguity of multiple leaves from an array, selecting only the one we need for each case. The variable filter is based on the same principle than the general Rules, but it contains only one set of rules, and filters an array of records from the root of the contact to the final leaf.

From our example, we can see that the contact “Johnny Bravo” has three communication Items: 2 phones and 1 email. To get this information into variables, we can apply the following filters:

<Variable Name="Email" Path="result.communicationItems.value">

    <Filter>

        <Rule Type="Equals" Ethalon="Email">result.communicationItems.type.name</Rule>

        <Rule Type="Equals" Ethalon="Email">result.communicationItems.communicationType</Rule>

    </Filter>

</Variable>

<Variable Name="DirectPhone" Path="result.communicationItems.value">

    <Filter>

        <Rule Type="Equals" Ethalon="Direct">result.communicationItems.type.name</Rule>

        <Rule Type="Equals" Ethalon="Phone">result.communicationItems.communicationType</Rule>

    </Filter>

</Variable>

<Variable Name="MobilePhone" Path="result.communicationItems.value">

    <Filter>

        <Rule Type="Equals" Ethalon="Cell">result.communicationItems.type.name</Rule>

        <Rule Type="Equals" Ethalon="Phone">result.communicationItems.communicationType</Rule>

    </Filter>

</Variable>

Each variable has the same path but different filters, so the engine reads the proper value for each variable.

Outputs element

After filling the variables with the values taken from the data returned by the server, we need to complete the output of the scenario, that means the result of all this processing. To do this, we use the <Outputs> element. There are 2 different types of outputs:

  1. To provide output values: this stops the scenario chain processing. In this case the <Outputs> element has as many children <Output> elements as we need, one for each output value.
  2. To run another (chained) scenario: in this case the Next attribute is set to the Id of the following scenario, and the output will be provided by the next scenario instead of this.

The scenario providing output values can do it in 2 cases:

  1. When there is at least one record that matches the scenario rules.
  2. When the AllowEmpty attribute is set to true.

The attributes of the <Outputs> element are the following:

  • Next (string) - Id of the following scenario to execute, if any.
  • AllowEmpty (bool) - When true, the scenario provides an output even when there is no record that matches the scenario rules, or when the whole request has been skipped. In this case the output will have an empty value for all values.
    This is useful if you want to skip some intermediate scenario in a chain, due to some reason. For example, you need one request to get the main contact data (first name, last name, company id, etc.) and a second chained request to get the company name by its id. If the contact is not associated with a company, the second request will return no records. In this case, if AllowEmpty is not specified, it will not return any information from this contact, and that is incorrect as the contact is still valid.

When the <Outputs> element provides output values, it contains children <Output> elements. Each child <Output> element has the following attributes:

  • Type (string) - The type of the output value. See section Output for each type of scenario for more details.
  • Value (string Expression) - The expression to create the value to output.

For example, the following output sets the result for a contact lookup, using expressions to include variables:

<Outputs>

    <Output Type="ContactUrl" Value="https://[Domain]/[Version]/ConnectWise.aspx?routeTo=ContactFV%26recid=[Id]"/>

    <Output Type="FirstName" Value="[FirstName]"/>

</Outputs>

Output for each type of scenario

There are 4 types of scenarios:

  • Phone Number Matching Scenario
  • Authentication Scenario
  • OAuth Response Scenario
  • Chained Scenario

Phone Number Matching Scenario

This scenario does not have an Id, and it’s possible to have many scenarios of this type for a single template. In case of having more than one scenario of this type, they will be executed one after the other, in the same order as they are placed in the template, and the result will be concatenated.

The output types for this scenario are the following: (All are string Expression)

  • FirstName - First name of the contact
  • LastName - Last name of the contact
  • Email - Email of the contact
  • CompanyName - Company name of the contact
  • ContactUrl - URL of the contact in the CRM
  • PhoneMobile - Mobile phone of the contact
  • PhoneMobile2 - Additional mobile phone of the contact
  • PhoneHome - Home phone of the contact
  • PhoneHome2 - Additional home phone of the contact
  • PhoneBusiness - Business phone of the contact
  • PhoneBusiness2 - Additional business phone of the contact
  • PhoneOther - Otherr phone of the contact
  • FaxBusiness - Business fax of the contact
  • FaxHome - Home fax of the contact
  • Pager - Pager of the contact

Authentication Scenario

Only one authentication scenario is allowed per template. This scenario is triggered from the Authentication section, matching the Id to the Value specified there.

The Authentication Scenario is invoked in the following cases:

  1. On the first query to the CRM.
  2. When the timeout is expired, or the timeout is not specified and the last invocation to the authentication scenario was made more than 1 hour ago.

The output types for this scenario are the following:

  • Bearer (string Expression) - If provided, the Bearer value to use in the Authentication header for each request sent.
  • BearerExpiration (integer Expression) - Timeout in seconds for bearer expiration. The Authentication Scenario will not be invoked again until this timeout expires.
  • HeaderName (string Expression) - If provided, name and value of custom request header to use on each request to the CRM.
  • HeaderValue string Expression (string Expression) - If provided, name and value of custom request header to use on each request to the CRM.

Note: at least one header should be provided: Bearer or HeaderName/HeaderValue.

OAuth Response Scenario

This type of scenario is invoked by the OAuth response, when the 3CX Management Console is triggered by the external OAuth server when granting permission. This type of scenario has also access to the query string parameters of the original request.

The output types for this scenario are the following:

  • Result (string Expression) - Value that will be set to the associated parameter.

Chained scenario

Any of the previous types of scenarios can invoke a chained scenario to complete the task. In that case, a chained scenario is configured as output, and that scenario will provide the actual output. The chained scenario is executed for each result returned by the Rules filters. For example, this output invokes a chained scenario with Id “GetContactId”:

<Outputs Next="GetContactId"/>

A chained scenario has access to every variable set in a parent scenario.

The scenario execution chain ends in two cases:

  1. The last scenario is reached and outputs are set.
  2. The scenario’s request produces an empty response (or there are no records that pass the filter) and the AllowEmpty attribute for the output is set to false.

Expressions

The expressions engine allows us to build values using:

  • Variables
  • String concatenation
  • Method invocation
  • Condition evaluation

Variables

To get a variable value, use the variable name between square brackets:

[SomeVariable]

Variables are obtained from:

  1. Predefined variables
  2. Input parameters
  3. Scenario variables

In case you need to specify the square brackets as a string literal, you need to use a pair of braces instead. For example:
{{ represents [

}} represents ]

Predefined variables

The following variables are predefined and can be used at any time:

  • Number (string) - Phone number to search modified according to the Number element.
  • DestinationEmail (string) - Email address of the destination extension (currently not in use, reserved for future versions).
  • MaxLength (integer) - Number of digits to match (counted from right to left).
  • FoundRecordCount (integer) - Total number of contacts returned. It is determined when the matching scenario chain has finished.
  • _oAuthResp (string) - Relative path to the Management Console URL that triggers the OAuth Response Scenario.

String concatenation

By default, the expression engine will concatenate the strings found in an expression. For example, if an expression contains variables and string literals:

<Authentication Type="Basic">

        <Value>[CompanyName]+[PublicKey]:[PrivateKey]</Value>

</Authentication>

The value will be the result of concatenating the value of the variable [CompanyName], then the “+” string literal, then the value of the variable [PublicKey], then the “:” string literal, and finally the value of the variable [PrivateKey].

Another example to build the URL for a request:

<RequestUrl="[Domain]/rest/v10/Contacts?filter{{0}}{{phone_mobile}}{{$ends}}=[Number]&amp;fields=id,first_name,last_name,phone_mobile,email,accounts" ResponseType="Json"/>

There, [Domain] is an input parameter, and [Number] is the predefined variable containing the phone number to search. The remaining text is considered string literal, and will be concatenated with the values of these variables.

To leave the string concatenation mode and enter the methods invocation and condition evaluation modes, you need to put the expression content inside square brackets, as shown in the following sections.

Method invocation

You can invoke any supported method on the value of a variable using this syntax:

[[Variable].MethodName(param1;param2;...paramN)]

For example, to replace a “+” with the string “%2B” to perform URL encoding on the number to search, we can use the following expression:

[[Number].Replace(&quot;+&quot;,&quot;%2B&quot;)]

Condition evaluation

The engine supports the following operators:

  • == (bool) - Compares two strings and returns true if they are equal
  • != (bool) - Compares two strings and returns true if they are not equal.
  • > (bool) - Compares two IComparable objects, and returns true if the first is greater than the second.
  • + (integer float string) - Returns the addition of two objects, according to their type.
  • - (integer float) - Returns the subtraction of two objects, according to their type.
  • IIf(cond,res1,res2) - Returns res1 when cond is true, otherwise returns res2.

Example: https://[IIf([IsCloud]==true,"api-","")][Domain]...

In this case, when variable [IsCloud] is set to true, the string value “api-” will be added to the value of the [Domain] variable, to create the proper URL. Please note the square brackets around the “IIf” operator.

Debugging

The 3CX service is responsible for executing the server side CRM engine, for every inbound call to the system. This service loads the templates during startup, and keeps them in memory as long as the process is running. Therefore, any change to a template requires the 3CX service to be restarted, for the changes to be applied.

In order to debug a template without making many calls to the system, it’s possible to emulate an inbound call from a particular number, by making a GET request to a specific URL:

https://<Management_Console_URL>/api/CrmList/test?num=<Phone number>&ext=<Ext>

The output will be JSON with all the matched contacts returned by the CRM.

The file “3cxSystemService.log” contains logs for real CRM integration processing. While the file “3cxManagementConsole.log” contains logs for debug CRM integration processing through the management console URL. Switch to verbose for more details.

You might also be interested in:

Get 3CX Free for 1 Year Today
Download On-Premise Try in the Cloud