# Add a CRM Integration Template

When the CRM you want to connect isn't already available as a ready-made integration, you can define your own. A custom integration template describes how Cloud Voice authenticates with the CRM and which API requests it sends, letting the two systems exchange and synchronize data. This page walks through creating a template and filling in the settings your CRM requires.

## Requirements

- **Cloud Voice server**
  - **Firmware**: version 84.23.0.123 or later.
  - **Plan**: Enterprise Plan (EP) or Ultimate Plan (UP).
- **CRM**: exposes a REST API.

You can add up to **10** custom CRM integration templates.

## Before you start

- You are comfortable with basic coding and JSON.
- You have your CRM's REST API documentation on hand and have gathered the following.

**Authentication details**

Identify the authentication method the CRM uses. Cloud Voice supports None, Basic, OAuth2, and Bearer Token. If the CRM uses **OAuth2** or **Bearer Token**, collect these endpoints and their data specifications:

| Endpoint | Purpose |
| --- | --- |
| Authorization | The URL users are redirected to for sign-in and consent. |
| Get access token | The API request that returns an access token. |
| Refresh access token | Optional. The API request that returns a refresh token. |

**API request details**

Based on what the CRM can do and what you need, collect the request URLs and data specifications for the functions you plan to use:

| Function | Purpose |
| --- | --- |
| Search contacts | Request URLs that look up contacts in the CRM by specific criteria. |
| Get users | Optional. The request that returns the CRM's user list. |
| Create contacts | Optional. The request that adds a new contact to the CRM. |
| Call journaling | Optional. The request that creates and/or updates call records in the CRM. |
| Chat journaling | Optional. The request that creates an object (such as a task) to hold synced chat data. |

:::note
To pull in a large number of users, also note the CRM's pagination parameters (such as `page`, `pageSize`, `limit`, or `offset`) so you can retrieve users in batches.
:::

## Create the template

1. Sign in to the Cloud Voice web portal and open **Integrations > CRM**.
2. In the CRM list, click **Custom**. You are taken to the Template Management page.

   ![The CRM list with the Custom option for building your own integration](/images/pbx/crm-template-entry.png)

3. Click **Add**.
4. In the pop-up, complete the template settings your CRM and use case call for. The sections that follow describe each area, in the order you'll typically work through them:

   1. [General settings](#general-settings)
   2. [User association](#user-association-optional) (optional)
   3. [Authentication method](#set-the-authentication-method)
   4. [Request headers](#request-headers-optional) (optional)
   5. [Follow-up requests](#follow-up-requests-optional) (optional)
   6. [Connection keepalive](#connection-keepalive-optional) (optional)
   7. [Contact search, synchronization, and call pop-up](#contact-search-synchronization-and-call-pop-up)
   8. [New contact creation](#new-contact-creation-optional) (optional)
   9. [Call journaling](#call-journaling-optional) (optional)
   10. [Chat journaling](#chat-journaling-optional) (optional)

5. Click **Save** to generate the template.

## General settings

In the **General** section, fill in the template basics.

![The General section of a new CRM template](/images/pbx/crm-general-settings.png)

- **Logo**: Upload an image for the CRM. It appears next to the CRM in the list on the Integrations page.
- **CRM Name**: The name of the CRM.
- **Max Concurrent Request**: The most simultaneous HTTP requests Cloud Voice may send to the CRM.
- **Remark**: Optional. A description shown on the Template Management page.

:::note
The logo must be PNG (recommended), JPG, or JPEG, no larger than 500 KB. A resolution of 150 × 150 is suggested.
:::

:::tip
Keep **Max Concurrent Request** at or below the rate the CRM's API can handle. Many CRMs throttle or reject a client that sends too many requests at once, so match this value to any rate limit listed in the CRM's API documentation.
:::

## User association (optional)

In the **User Association** section, turn on and configure the ability to link CRM users to Cloud Voice extensions.

:::note
When this is on, whoever activates the integration must pair CRM users with extensions, and only the paired extension users can use the integration's features.
:::

![Extension users being matched to CRM users during setup](/images/pbx/custom-user-association.png)

1. Turn on **User Association**.

   ![The User Association toggle switched on](/images/pbx/turn-on-user-association.png)

2. In the **Get User** field, enter the CRM request URL that returns the list of CRM users.

   ![The Get User field holding the CRM endpoint that lists users](/images/pbx/get-user-endpoint.png)

   For example:

   ```text
   https://www.api.example.com/v1/users?type=ActiveUsers
   ```

   :::note
   - The default request method is `GET`. To use a different method, change it in the template later. For the parameters involved here, see the [user-association parameters in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__section_m1g_2th_r2c).
   - Values that users enter during [authentication](#set-the-authentication-method) can be reused as variables in this URL.
   :::

3. In the **Pagination Type** list, choose the mode that matches your CRM. For modes that make repeated requests, a single sync runs at most 100 requests.

   - **Disabled**: Cloud Voice sends a single request with no pagination parameters. Use this when the API returns every record in one response or doesn't paginate.
   - **Page Number Pagination**: Cloud Voice sends repeated requests based on page number and page size, incrementing the page number each time until all data is retrieved. Configure:

     ![Page number pagination parameters](/images/pbx/get-user-page.png)

     - **Page Parameter Name**: The parameter that carries the page number.
     - **Page Start Value**: The first page number to request.
     - **Page Size Parameter Name**: The parameter that sets records per page.
     - **Page Size Value**: The maximum records returned per page.
   - **Offset Pagination**: Cloud Voice sends repeated requests based on a starting offset and a record limit, raising the offset by the limit each time until all data is retrieved. Configure:

     ![Offset pagination parameters](/images/pbx/get-user-offset.png)

     - **Offset Parameter Name**: The parameter that sets the starting offset.
     - **Offset Value**: Where retrieval begins. `1` starts at the first record; `100` starts at the 100th.
     - **Limit Parameter Name**: The parameter that sets records per page.
     - **Limit Value**: The maximum records returned per page.
   - **Link Pagination**: Cloud Voice follows the "next page" URL in each response until no more pages remain. In **Next Page Link Path**, enter the JSON path to that URL, for example `links.next`.

     ![The Next Page Link Path field for link-based pagination](/images/pbx/get-user-link.png)

4. In **User Field Mapping**, map the CRM's response fields to the Cloud Voice fields by entering a JSON path (for example, `data.#(key=="value").field`) for each.

   ![Mapping CRM response fields to Cloud Voice user fields](/images/pbx/get-user-field.png)

   | Cloud Voice field | Description |
   | --- | --- |
   | User Unique ID | The user's unique ID, for example `users.#.id`. |
   | First Name | The user's first name, shown in the CRM user list, for example `users.#.First_Name`. |
   | Last Name | The user's last name, shown in the CRM user list, for example `users.#.Last_Name`. |
   | Email | The user's email, shown in the CRM user list and usable to match CRM users to extensions automatically, for example `users.#.Email`. |

   :::tip
   For the JSON path syntax, see the [GJSON path syntax reference](https://github.com/tidwall/gjson/blob/master/README.md#path-syntax).
   :::

## Set the authentication method

In **Request Configuration > Authentication Method**, pick the method your CRM expects: [None](#none), [Basic](#basic), [OAuth2](#oauth2), or [Bearer Token](#bearer-token).

Several methods let you add **custom fields** that appear as inputs on the integration page, so whoever activates the integration can supply the details it needs. Values that users type into these fields are stored as global variables and can be referenced anywhere in the template. Each custom field has the following settings:

| Setting | Description |
| --- | --- |
| Type | The field type: **Text Input** for plain text, **Password Input** for masked sensitive values, or **Dropdown List** to choose from preset options. |
| Name | The variable name used to reference the field elsewhere in the template. |
| Title | The label shown above the input. |
| Dropdown Options | For a **Dropdown List**, the available options, separated by commas (for example, `option1,option2`). |

### None

Use this when the CRM needs no authentication, or only needs certain values for the integration such as an API key or a webhook URL for real-time delivery.

![The None authentication option with optional custom fields](/images/pbx/none-auth.png)

1. In the **Authentication Method** list, select **None**.
2. Optionally, click **Add** to create custom fields for the details users must provide.

:::note
- With no fields added, the CRM connects directly with no extra input from users.
- You can add up to 5 custom fields.
:::

### Basic

Every request to the CRM carries an `Authorization: Basic {{.basic_string}}` header, where `{{.basic_string}}` is the Base64-encoded username and password or API key supplied during setup.

![Basic authentication settings](/images/pbx/basic-oauth.png)

1. In the **Authentication Method** list, select **Basic**.
2. In the **Credential Type** list, select **Username and Password** or **API Key**, matching what the CRM requires.
3. Set up the fields users fill in for their credentials, and add custom fields if needed (up to 5 fields total).
4. In **Base64 Encoded Credential**, define how the credential variables combine to build the `basic_string`, for example `{{.username}}:{{.password}}` or `{{.api_key}}`.

### OAuth2

This method uses tokens to grant access without sharing credentials, obtaining the token and related values through specific requests to the CRM. Both the **Standard Authorization Code** flow and the **Authorization Code with PKCE** (Proof Key for Code Exchange) flow are supported.

1. Set the method and authorization mode.

   ![Selecting OAuth2 and an authorization mode](/images/pbx/select-oauth2.png)

   1. In the **Authentication Method** list, select **OAuth2**.
   2. In the **Authorization Mode** list, choose a mode:

      | Mode | Description |
      | --- | --- |
      | Standard Authorization Code | Requires a `client_secret`. Use it when the CRM expects a `client_secret`. |
      | Authorization Code (PKCE) | Makes `client_secret` optional and adds a layer of security. Cloud Voice generates a `code_verifier`, derives a `code_challenge` from it (SHA256 hashed and Base64URL encoded), and sends the challenge upfront. It keeps the `code_verifier` and presents it during token exchange; the server re-derives the challenge and compares. A match proves the same client is exchanging the code, which blocks interception attacks. |

2. Set up the fields users fill in for their credentials.

   ![Credential fields users complete for OAuth2](/images/pbx/oauth2-input.png)

   :::note
   - You can add up to 10 fields here. For more, add custom fields in the template later; see the [authentication parameters in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__section_lvt_dth_r2c).
   - In addition to the common field settings, an OAuth2 field has a **Required** setting: **Yes** makes the field mandatory, **No** lets users leave it blank.
   :::

3. Configure the OAuth2 authorization settings.

   ![OAuth2 authorization endpoint and token settings](/images/pbx/oauth2-token-setting.png)

   | Setting | Description |
   | --- | --- |
   | Authorization Endpoint | The CRM authorization URL users are redirected to during setup, for example `https://www.api.example.com/auth/v2/authorize?client_id={{.client_id}}`. |
   | Token Endpoint | The CRM request URL that returns the access token and refresh token, for example `https://www.api.example.com/oauth/v2/token?client_id={{.client_id}}&client_secret={{.client_secret}}`. |
   | Content Type | The content type of the token retrieval request. |
   | PKCE Verification Method | How the `code_verifier` becomes the `code_challenge`. Available only when **Authorization Mode** is **Authorization Code (PKCE)**. **S256** hashes with SHA256 and encodes with Base64URL (recommended); **Plain** uses the `code_verifier` as-is for CRMs without SHA256 support. |
   | Scope | Optional. The CRM data Cloud Voice may access, with multiple scopes separated by commas, for example `contacts.read,contacts.write,calls.read,calls.write,user.read,user.write`. |
   | Additional Query String | Optional. When the CRM authenticates with query parameters instead of a scope, add them here, for example `client_id={{.client_id}}&redirect_uri={{.redirect_uri}}`. |

4. Optionally, configure token refresh.

   ![Token refresh settings](/images/pbx/oauth2-token-refresh-setting.png)

   | Setting | Description |
   | --- | --- |
   | Token Refresh Request Method | The HTTP method for the refresh request. |
   | Token Refresh Endpoint | The request URL that refreshes the access token. |
   | Token Refresh Content Type | The content type of the refresh request. |
   | Token Refresh Time (min) | How often, in minutes, to refresh the token automatically. `0` disables automatic refresh; leaving it blank refreshes every 25 minutes. |
   | Token Refresh Request Body | The body of the refresh request. |

   :::caution
   If the CRM's access tokens expire, leave **Token Refresh Time (min)** blank or set a value shorter than the token's lifetime. Setting it to `0` turns automatic refresh off, so once the current token expires every request to the CRM fails until someone re-authorizes the integration.
   :::

### Bearer Token

Every request to the CRM carries an `Authorization: Bearer {{.AccessToken}}` header, where `{{.AccessToken}}` is a token granted by the CRM (typically through an authorization process such as OAuth2).

1. In the **Authentication Method** list, select **Bearer Token**.

   ![Selecting Bearer Token as the authentication method](/images/pbx/select-bear.png)

2. Set up the fields users fill in for their credentials, and add custom fields if needed (up to 10 fields).

   ![Credential fields users complete for bearer token authentication](/images/pbx/bear-input-setting.png)

3. Configure token retrieval to match the API.

   ![Token retrieval settings for bearer token authentication](/images/pbx/bear-token-setting.png)

   | Setting | Description |
   | --- | --- |
   | Token Endpoint | The CRM request URL that returns an access token, for example `https://www.api.example.com/oauth/v2/token?client_id={{.client_id}}&client_secret={{.client_secret}}&grant_type=client_credentials`. The returned token is stored in `{{.AccessToken}}`. |
   | Content Type | The content type of the token retrieval request. |

4. Optionally, configure token refresh using the same fields described under [OAuth2](#oauth2).

   ![Token refresh settings](/images/pbx/oauth2-token-refresh-setting.png)

## Request headers (optional)

Add custom HTTP headers that Cloud Voice includes in its predefined CRM sync requests (user association, contact sync, and so on).

:::note
- You can add up to 20 custom headers.
- These headers are not applied to authentication requests (such as getting or refreshing a token) or to custom-configured requests.
:::

:::caution
Don't define an `Authorization` header here. It would override the header produced by the Basic, OAuth2, or Bearer Token flow.
:::

![Adding a custom HTTP header to the template](/images/pbx/custom-crm-header.png)

1. In **Request Configuration > Headers**, click **Add**.
2. Configure the header.

   | Setting | Description |
   | --- | --- |
   | Name | The header name, such as `Content-Type` or `Accept`. |
   | Value | The header value, either literal or a variable. Variables defined for the authentication method work here too; for example, reference a `client_id` variable as `{{.client_id}}`. |
   | Description | A short note on what the header is for. |

## Follow-up requests (optional)

If your integration needs extra operations after certain predefined requests finish, add follow-up requests. Each one fires automatically when its specified operation succeeds, and you can pull values out of its response into global variables for reuse elsewhere.

:::note
You can add up to 10 follow-up requests.
:::

![Configuring a follow-up request](/images/pbx/followup-requests.png)

1. In **Request Configuration > Follow-up Requests**, click **Add**.
2. Configure the request.

   | Setting | Description |
   | --- | --- |
   | Triggered Event | The event that fires this follow-up request. |
   | Request Method | The HTTP method for the request. |
   | URL | The endpoint URL, for example `https://api.example.com/rest-services/login`. |
   | Headers | The request headers as a JSON object, with `{{.varname}}` for dynamic values, for example `{"Content-Type":"application/json", "X-Custom-Header": "{{.DynamicValue}}"}`. |
   | Request Body | The request payload as a JSON object, with `{{.varname}}` for dynamic values, for example `{"lastName":"{{.LastName}}","ownerId":"{{.Id}}","phone":"{{.BusinessNumber}}"}`. |
   | Response Field Path | The JSON path(s) to extract from the response, separated by commas, for example `.data.access_token, .tokens[0].value`. |
   | Target Variable Name | The variable(s) that store the extracted values, either existing or new, separated by commas (for example, `token,refresh`). Variables receive values in the same order as the paths in **Response Field Path**. Stored values are global and reusable throughout the integration. |

## Connection keepalive (optional)

Keep the connection from dropping after a network timeout or a period of inactivity. When enabled, Cloud Voice sends keep-alive requests at the interval you set to check the connection and confirm authentication is still valid.

![Connection keepalive settings](/images/pbx/connection-keepalive.png)

1. Turn on **Connection Keepalive**.
2. In **Keepalive Interval (minutes)**, set how often the keep-alive request is sent.

## Contact search, synchronization, and call pop-up

In the **Synchronize Contacts Automatically** section, define the contact types users can pick from and the requests that look those contacts up. These settings power contact search, automatic contact synchronization, and the call pop-up.

1. Add a contact type and its lookup request.

   ![Defining a contact type and its match query URL](/images/pbx/add-crm-contact.png)

   - **Contact Type**: A name such as `Contacts`. It appears as an option for automatic contact synchronization when users configure the integration.
   - **Contact Match Query URL**: The CRM request URL that searches for contacts by criteria. You can use these variables in the criteria:
     - Values users entered during [authentication](#set-the-authentication-method).
     - Target variables extracted from [follow-up requests](#follow-up-requests-optional).
     - `{{.Phone}}`: the number on an inbound or outbound call, or the number a user types when searching.

     For example:

     ```text
     https://www.api.example.com/crm/v1/Contacts/search?criteria=((Phone:equals:{{.Phone}})or(Home_Phone:equals:{{.Phone}})or(Mobile:equals:{{.Phone}})or(Asst_Phone:equals:{{.Phone}}))
     ```

2. Set the call pop-up URL with one of the following methods.

   **Specify URL Format**

   Build the URL yourself from an expression, using variables to fill it in dynamically.

   ![Building the contact pop-up URL from a URL format](/images/pbx/specify-url-format-helpdesk.png)

   1. In the **Contact Popup URL** list, select **Specify URL Format**.
   2. In **URL Format**, enter the expression. The following variables draw their values from the contact search results:
      - Values users entered during authentication.
      - Target variables extracted from follow-up requests.
      - `{{.ContactSyncType}}`: the contact type.
      - `{{.ContactId}}`: the contact ID.
      - `{{.CustomValue}}`: a field mapped in **Contact Field Mapping**.

      For example:

      ```text
      {{.crm_url}}/crm/{{.CustomValue}}/tab/{{Capitalize .ContactSyncType}}/{{.ContactId}}
      ```

   :::note
   If these variables don't cover what you need, edit the template later to define additional custom variables and retrieve their values. See the [additional-variable parameters in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__global).
   :::

   **Retrieve from Contact Fields**

   Read the URL straight from a field in the contact search response.

   ![Reading the contact pop-up URL from a response field](/images/pbx/retrieve-url-from-fields.png)

   1. In the **Contact Popup URL** list, select **Retrieve from Contact Fields**.
   2. In **Contact Field for URL**, enter the JSON path to the field, for example `data.#.contactUrl`.

3. In **Contact Field Mapping**, map the CRM's response fields to the Cloud Voice fields with a JSON path (for example, `data.#(key=="value").field`).

   :::note
   - Mapped values retrieved during a call are stored as variables you can reference across modules until the call ends.
   - To pull more than one variable into a field, separate them with commas. This applies only to phone number fields, for example `data.#(phone=="{{.Phone}}")#.phone,data.#(mobile=="{{.Phone}}")#.mobile`.
   :::

   1. Map the required fields.

      ![Mapping the required Contact ID and First Name fields](/images/pbx/required-pbx-field.png)

      - **Contact ID**: the ID of the found contact, for example `data.0.id`.
      - **First Name**: the first name of the found contact, for example `data.0.First_Name`.

   2. Enable and map any other fields you need. You must enable and map at least one phone number.

      ![Mapping optional contact fields, including phone numbers](/images/pbx/optional-mapping-contact-field.png)

   3. If no existing field gives you the value you need, enable and map the response field to **Custom Value**, then reference it as `{{.CustomValue}}`.

      ![Mapping a response field to the Custom Value field](/images/pbx/custom-value.png)

      :::note
      `{{.CustomValue}}` is meant for building the contact URL and does not appear in Cloud Voice contact details.
      :::

## New contact creation (optional)

To create a new CRM contact when a caller's number matches nothing in the CRM, turn on and configure **Create New Contact**.

![The Create New Contact settings](/images/pbx/auto-create-crm-contact.png)

1. Turn on **Create New Contact**.
2. Add the contact types users can choose from when configuring the integration.
   - **Contact Type**: The type of contact, for example `Contacts`.
   - **Contact Creation URL (POST)**: The CRM request URL that creates a contact, for example `https://www.api.example.com/crm/v1/Contacts`.
   - **Contact Creation Request Body**: The request body (JSON) that carries the contact details. You can use these variables:
     - Values users entered during authentication.
     - Target variables extracted from follow-up requests.
     - `{{.LastName}}`: required. The contact's last name.
     - `{{.FirstName}}`: required. The contact's first name.
     - `{{.BusinessNumber}}`: required. The contact's phone number.

     For example:

     ```json
     {
       "data": [
         {
           "Last_Name": "{{.LastName}}",
           "First_Name": "{{.FirstName}}",
           "Phone": "{{.BusinessNumber}}"
         }
       ]
     }
     ```

:::note
If these variables don't cover what you need, edit the template later to define additional custom variables. See the [additional-variable parameters in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__global).
:::

## Call journaling (optional)

To log call activity and details into the CRM automatically, turn on and configure **Call Journal**.

![Call Journal settings with request URLs and bodies](/images/pbx/set-call-journal-helpdesk.png)

1. Turn on **Call Journal**.
2. Configure the request that creates a call log.
   - **Create Call Journal URL**: The CRM request URL that creates a call log, for example `https://www.api.example.com/v2/Calls`.
   - **Create Call Log Request Method**: **POST** or **PUT**.
   - **Call Journal Creation Request Body**: The request body (JSON) carrying the call details. For the variables you can use, see the [call-journal variables in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__var-2). For example:

     ```json
     {
       "data": [
         {
           "{{.Owner}}{{.WhoModule}}": {
             "Description": "{{.Description}}",
             "Voice_Recording__s": "{{.RecordPath}}",
             "Call_Start_Time": "{{TimeFormat .StartTimeUnix 'yyyy-MM-ddTHH:mm:ss-z' '1'}}",
             "Subject": "{{.Subject}}",
             "Call_Type": "Inbound",
             "Call_Result": "{{.Call_Log_Status}}",
             "Call_Duration": "{{.Talk_Duration_Sec}}"
           }
         }
       ]
     }
     ```

3. Optionally, configure the request that updates an existing call log with more information.
   - **Update Call Journal URL**: The CRM request URL that updates a call log, for example `https://www.api.example.com/v2/Calls/{{.CallId}}`.
   - **Update Call Log Request Method**: **POST** or **PUT**.
   - **Call Journal Update Request Body**: The request body (JSON) carrying the call details. For example:

     ```json
     {
       "data": [
         {
           "{{.Owner}}{{.WhoModule}}": {
             "Description": "{{.Description}}",
             "Voice_Recording__s": "{{.RecordPath}}",
             "Call_Start_Time": "{{TimeFormat .StartTimeUnix 'yyyy-MM-ddTHH:mm:ss-z' '1'}}",
             "Subject": "{{.Subject}}",
             "Call_Type": "Inbound",
             "Call_Result": "{{.Call_Log_Status}}",
             "Call_Duration": "{{.Talk_Duration_Sec}}",
             "AI_Transcription": "{{.AI_Transcription}}",
             "AI_Summary": "{{.AI_Summary}}",
             "Call_Note": "{{.Call_Note}}"
           }
         }
       ]
     }
     ```

4. Optionally, choose which call-journal options appear in the integration. Select an option's checkbox to expose it, and set its default value.

   | Option | Description |
   | --- | --- |
   | Subject | Lets the integration set a default subject for all synced call logs. |
   | Description | Lets the integration set the details of synced call logs, for example `Call: {{.Time}} {{.Call_Log_Status}} from {{.Call_From}} to {{.Call_To}} {{.Talk_Duration}}`. |
   | Play Call Recording | Lets the integration control whether call recordings can be played back within the CRM. |
   | Disable Display Missed Call Records in Unanswered Agents | Lets the integration sync queue and ring group call logs only to the CRM of the agent who answered, keeping missed-call logs for the same call out of the CRM of agents who didn't. |

   :::note
   Values set in these fields can also be captured as variables where needed. For the supported variables, see the [call-journal variables in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__var-2).
   :::

## Chat journaling (optional)

To sync chat messages with CRM contacts into the CRM automatically, turn on and configure **Chat Journal**.

![Chat Journal settings](/images/pbx/template-chat-journal.png)

1. Turn on **Chat Journal**.
2. Configure the request that stores chat messages.
   - **Create Chat Journal URL (POST)**: The CRM request URL that creates an object to hold chat messages, for example `https://www.api.example.com/v2/Tasks`.
   - **Chat Journal Creation Request Body**: The request body (JSON) carrying the chat details. For the variables you can use, see the [chat-journal variables in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__var-chat-journal). For example:

     ```json
     {
       "data": [
         {
           "Owner": {
             "id": "{{.OwnerId}}"
           },
           "Who_Id": "{{.ContactEntityId}}",
           "Subject": "{{.Subject}}",
           "Due_Date": "{{ TimeFormat .StartTimeUnix "yyyy-MM-dd" "0" }}",
           "Closed_Time": "{{ TimeFormat .EndTimeUnix "yyyy-MM-ddTHH:mm:ss.000Zz" "0" }}",
           "Status": "Completed",
           "Priority": "Normal",
           "Description": "Message Channel Type: {{.Channel_Display}}\n\n{{.Messages}}"
         }
       ]
     }
     ```

3. Optionally, in the **Subject** section, decide whether users can customize the subject of the synced record.
   1. Select the checkbox to expose the **Subject** field in the integration.
   2. Set its default value.

   :::note
   Values set in this field can also be captured as variables where needed. For the supported variables, see the [chat-journal variables in the XML reference](/pbx/integrations/xml-descriptions-for-integration-template/#crm-integration-template-xml-description__var-chat-journal).
   :::
