TryLearn More

Use SIP trunks, WebRTC & Apps

Slash your Phone Bill by 80%

CRM template XML description

On this topic

CRM template XML description


The XML template format

Number element

Connection element

Parameters element

Authentication element

Scenarios element

Request element





Outputs for each type of scenario

Phone Number Matching Scenario

Authentication Scenario

OAuth Response Scenario

Chained scenario

Creating OAuth2 authentication flow



Predefined variables

String concatenation

Method invocation

Condition evaluation

Call Journaling



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

<Crm> is the root element of the XML template. This contains

  • 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 contains the following child 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.

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.

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 four types available at the moment: String - represents a string, Password represents a string hidden in a user interface, Boolean represents a checkbox, OAuth - represents a button to trigger the OAuth authentication flow.
  • Title (string) Caption to show in the 3CX Management Console for this parameter.
  • 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.
  • RequestUrlParameters (String Expression) OAuth parameters which will be concatenated with RequestUrl 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 (see Parameters node in Zoho template):

Authentication element

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

  • No authentication: Type="No" 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.
  • Basic authentication: Type="Basic" 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.
  • Scenario authentication: Type="Scenario" 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 and/or other parameters that we need to use for requests (for example, OAuth access token), the token expiration, etc. using specific requests to the CRM.

Please note that not only Outputs but all Variables captured or declared within authentication scenario are accessible for subsequent requests.

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: It fills variables taken from the response data and provides an output or calls an inner scenario recursively by id.

The Scenario element has an attribute named Id (String) which can contain a 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. Id=”auth” means that the Authentication scenario will be invoked. Leaving this empty will use the contact number scenario. There are 4 elements in the Scenario node: Request,

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.
  • RequestEncoding (enum) The encoding used for POST request. Valid values are: Json,  UrlEncoded. When Json is selected you can build advanced Json objects by using nodes <Object/>, <Array/>. Please see example in Zoho template, scenario ReportCall.
  • 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
  • <Value /> node supports optional attributes If and SkipIf. Which help to build request based on conditions.

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:


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.

This is an example of a JSON request returned by the CRM Provider

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 above JSON example we can see that:

  • 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 “” points to the 4 leaves with values: “Direct”, “Email”, “Cell” and “Direct”.

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

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:

..this will result a single record for “Hannibal Lecter”.

By comparison, using the following rule

..will match 4 records, 3 for “Johnny Bravo” and 1 for “Hannibal Lecter”.

If we change the rules as follows:

..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”.


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:

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

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.


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:

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


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:

  • 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.
  • 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 for each type of scenario

There are 4 types of scenarios:

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. We recommend to set this parameter one minute less than your real expiration timeout to avoid expiration errors.
  • 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 should be 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.

Creating OAuth2 authentication flow

For a complete example see Zoho and ExactOnline templates.

  1. Get ClientId and ClientSecret from your CRM provider.
  2. Allow 3CX PhoneSystem OAuth2 URL in your CRM provider. It should be set to (for example)”
  3. Create Parameter with type OAuth inside Parameters section. This will be used to get authorization token. In RequestUrl and RequestUrlParameters attributes you can use other Parameter values. RequestUrlParameters will be automatically urlencoded while RequestUrl will remain intact. Please consult your CRM provider on how to build parameters for getting authorization token. It’s mandatory to pass special parameter [State] and [RedirectUri]. You can pass [State] separately (see Zoho) or concatenate it with [RedirectUri] (see ExactOnline). Usually at least client_id and redirect_url parameters are mandatory.
  4. Create response scenario which will be used to get refresh token and set it’s name to ResponseScenario attribute. Please consult your CRM provider on how to get refresh token. Usually this is a POST Json request and at least client_id and client_secret parameters are mandatory.
  5. Create Authentication node with Type=”Scenario” and create a scenario to get access token. Please consult your CRM provider on how to get access token. Usually this is a POST Json request and at least refresh_token, client_id and client_secret parameters are mandatory.


The expressions engine allows us to build values using:

  • Variables
  • String concatenation
  • Method invocation
  • Condition evaluation


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

Variables are obtained from:

  • Predefined variables
  • Input parameters
  • 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 [ and }} 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.

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">



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"/>

...where, [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:


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


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.
  • || (bool) - Conditional OR.
  • + (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 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 that act around the “IIf” operator.

Call Journaling

3CX PhoneSystem supports reporting external calls to CRM. To support call journaling one needs to create scenario with a reserved name “ReportCall”. You can skip <Rules/> and <Outputs/> nodes.  In this scenario one can use additional variables:

  • CallType - Type of a call, can be Inbound, Outbound, Missed, Unanswered
  • Number - external contact number dialed or calling
  • Name - external contact display name dialed or calling how it is known inside 3CX PhoneSystem
  • Agent - number of 3CX PhoneSystem extension handling the call
  • Duration - duration of a call in a format hh:mm:ss
  • DateTime - Local start time of a call formatted in 3CX PhoneSystem culture.
  • CallStartTimeUTC - UTC start time of a call as an object which can be formatted as user wants.
  • CallStartTimeLocal - Local start time of a call as an object which can be formatted as user wants.

Example see Zoho and Freshdesk templates.


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 use Test button in CRM Integrations page.

Free for up to 1 year! Select preferred deployment:


for Linux on a $200 appliance or as a VM

Get the ISO


for Windows as a VM

Download the setup file

On the cloud

In your Google, Amazon, Azure account

Take the PBX Express