# Integration Template XML Reference

Cloud Voice lets you build your own CRM (Customer Relationship Management) or Helpdesk integration by writing an XML template that describes the API endpoints, data fields, and automation scenarios the connection needs. This page is the reference for that template: it walks through the syntax conventions, the main elements, and every attribute and variable you can use in each scenario.

## Template conventions

Templates conform to the **XML 1.1** specification. Before working through the individual scenarios, it helps to understand how variables, functions, and the top-level elements fit together.

### Variables

A template uses variables wherever data needs to be filled in at run time. When the template runs, each variable reference is swapped for its current value.

**Where variable values come from**

A variable can draw its value from three places:

1. Built-in values that Cloud Voice already tracks, such as call details.
2. Values a user types in while setting up the integration.
3. Values pulled out of an API response. You address the field you want with a JSON path inside an `<Output>` element, for example:

   ```xml
   <Output Name="UserUniqueId" Path="data.#.id"></Output>
   ```

   To pull a value that matches a condition, use a filtered path:

   ```xml
   <Output Name="BusinessNumber2" Path="identities.#(type==&quot;phone_number&quot;)#|1.value"></Output>
   ```

:::tip
Path expressions follow GJSON path syntax. If a path isn't matching what you expect, check that syntax first.
:::

**How to reference a variable**

References use the Go `text/template` syntax:

- Plain variable: `{{.varname}}`
- Conditional: `{{ if .varname }} Welcome, member! {{ else }} Please sign up. {{ end }}`
- Passed through a function: `{{ Capitalize .varname }}`

### Functions

Functions transform or reformat a variable's value inline. The template supports the following.

| Function | What it does | Example |
|----------|--------------|---------|
| `TimeFormat` | Reformats a timestamp, optionally converting it to UTC. Format: `{{ TimeFormat <timestamp> "<format>" "<to-UTC>" }}`. | `{{ TimeFormat .StartTimeUnix "yyyy-MM-ddTHH:mm:ss.000Zz" "1" }}`, with `.StartTimeUnix` = `1672531199`, returns `2023-01-01T00:59:59.000Z`. |
| `ToMillis` | Converts a timestamp in seconds to milliseconds. | `{{ ToMillis .StartTimeUnix }}`, with `1672531199`, returns `1672531199000`. |
| `Capitalize` | Capitalizes the first letter of a string. | `{{ Capitalize .variable_string }}`, with `hello world`, returns `Hello world`. |
| `UrlEncode` | URL-encodes a string. | `{{ UrlEncode .variable }}`, with `hello world!`, returns `hello%20world%21`. |

### Template elements

A template is built from a small set of nested elements. The overall shape looks like this:

```xml
<Information>
  <Scenarios>
    <Scenario Id="1" Type="REST">
      <Parameters>
        <Parameter Name="example" Value="example"></Parameter>
        ...
      </Parameters>
      <Requests>
        <Request Name="ExampleRequest" Method="GET" URL="https://api.example.com/getuser">
          <Outputs>
            <Output Name="ContactId" Path="data.#.id" Type="string"></Output>
            ...
          </Outputs>
        </Request>
      </Requests>
    </Scenario>
  </Scenarios>
</Information>
```

| Element | Purpose |
|---------|---------|
| `<Information>` | The root element. Its attributes carry the template's basic details and feature switches (see [Template properties](#template-properties)), and it holds the `<Scenarios>` block. |
| `<Scenarios>` | A collection of `<Scenario>` elements. Cloud Voice loads each configured scenario and runs the requests or operations defined inside it. |
| `<Parameters>` | A set of parameters tied to a scenario or request, dynamic values or configuration settings that get passed in the URL, body, or headers. |
| `<Requests>` | A collection of the HTTP requests a scenario makes to deliver its feature. |
| `<Outputs>` | Inside a request, a list of `<Output>` elements that pull specific fields out of the API response. |

The template supports these scenarios:

- Authentication
- User association
- Automatic contact synchronization
- Automatic contact creation
- Automatic ticket creation (Helpdesk only)
- Call journal
- Chat journal

:::note
If the built-in scenarios don't cover what you need, you can hand-edit the template to add extra behavior. See [Extended configurations](#extended-configurations).
:::

## Template properties

The attributes on `<Information>` describe the template and turn features on or off.

| Attribute | Description |
|-----------|-------------|
| `Provider` | The template type. Fixed to `crm` or `helpdesk`. |
| `Name` | The template's display name. |
| `Key` | A unique identifier for the template. |
| `Logo` | The filename of the logo. |
| `Remark` | A free-text note describing the template. |
| `Version` | The template version, for example `1.0.0`. |
| `AuthType` | The authentication method: `none`, `basic`, `oauth2`, or `bearertoken`. |
| `MaxConcurrentRequest` | The maximum number of HTTP requests allowed to run against the CRM/Helpdesk at once. |
| `UserAssociation` | Whether user association is on. `0` = off, `1` = on. |
| `CallJournal` | Whether call journaling is on. `0` = off, `1` = on. |
| `CreateNewContact` | Whether automatic contact creation is on. `0` = off, `1` = on. |
| `CreateNewTicket` | Whether automatic ticket creation is on. `0` = off, `1` = on. |
| `ChatJournal` | Whether chat journaling is on. `0` = off, `1` = on. |

## Authentication scenario

This scenario sets how Cloud Voice authenticates against the CRM/Helpdesk. A typical structure:

```xml
<Scenario Id="AuthMethod" Type="AUTH">
  <Presets></Presets>
  <Parameters>
    <Parameter Name="AuthMethod" Value="oauth2"></Parameter>
    <Parameter Name="AuthEndPoint" Value="https://api.example.com/oauth/v2/auth?client_id={{.client_id}}"></Parameter>
    <Parameter Name="TokenEndPoint" Value="https://api.example.com/oauth/v2/token?client_id={{.client_id}}&amp;client_secret={{.client_secret}}"></Parameter>
    <Parameter Name="ContentType" Value="application/json"></Parameter>
    <Parameter Name="Scope" Value="contacts.read,contacts.write,calls.read,calls.write"></Parameter>
    <Parameter Name="TokenRefreshInterval" Value="25"></Parameter>
    <Parameter Father="CustomFieldList" Name="client_id" Editor="password" Title="Client ID" Value="" IsDelete="0" IsRequired="1"></Parameter>
    <Parameter Father="CustomFieldList" Name="client_secret" Editor="password" Title="Client Secret" Value="" IsDelete="0" IsRequired="1"></Parameter>
    <Parameter Father="PopulateTemplateString" Name="X-Client-Id" Type="Header" Value="{{.client_id}}" Description="for client identification" />
    <Parameter Father="FollowUpList" Name="ffb425cb-565d-49cd-92be-3290d0ab5129" Type="FollowUpRequest" Value="" IsDelete="0">
      <Parameter Name="TriggeredEvent" Value="token_retrieved"></Parameter>
      <Parameter Name="RequestMethod" Value="post"></Parameter>
      <Parameter Name="Url" Value="https://api.example.com/v1/install/verify"></Parameter>
      <Parameter Name="ResponseFieldPath" Value=".data.access_token, .tokens[0].value"></Parameter>
      <Parameter Name="TargetVariable" Value="token,refresh"></Parameter>
    </Parameter>
    <Parameter Name="AuthMode" Value="pkce"></Parameter>
    <Parameter Name="CodeChallengeMethod" Value="S256"></Parameter>
  </Parameters>
  <Requests></Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `AuthMethod`. |
| `Type` | Fixed to `AUTH`, the scenario performs authentication. |

### Parameter element

Each `<Parameter>` uses these attributes:

| Attribute | Description |
|-----------|-------------|
| `Name` | The name of the authentication setting. |
| `Value` | The value of the authentication setting. |
| `Father` | Groups related child parameters under a parent type. See the parent parameters below. |

The authentication scenario recognizes three parent-parameter types, each acting as a container for a related group of settings:

- `CustomFieldList`, defines the fields users fill in to supply their credentials (Client ID, Client Secret, and so on) in the setup UI.

  :::note
  Values captured in these custom fields stay available to every later request in the template.
  :::
- `PopulateTemplateString`, defines custom HTTP headers added to every predefined synchronization request (user association, contact sync, and the like) sent to the CRM/Helpdesk.
- `FollowUpList`, defines one or more automated requests fired after a specific event, such as once a token has been retrieved.

**`CustomFieldList` (credential input fields)**

| Attribute | Description |
|-----------|-------------|
| `Name` | The variable name of the field, referenceable in the template. Set it to `client_id` and you can use `{{.client_id}}`. |
| `Editor` | The field type: `string` (plain text), `password` (masked text), or `list` (choose from preset options). |
| `Title` | The label shown above the field in the setup UI. |
| `Value` | The preset options, used only when `Editor` is `list`. Separate options with commas, for example `option1,option2`. |
| `IsRequired` | Whether the field is mandatory: `0` = optional, `1` = required. Available when `AuthMethod` is `oauth2`. |

**`PopulateTemplateString` (custom HTTP headers)**

| Attribute | Description |
|-----------|-------------|
| `Type` | Fixed to `Header`. |
| `Name` | The header name. |
| `Value` | The header value, a literal string or a variable. You can reference a credential variable here, for example `{{.client_id}}`. |
| `Description` | A short note explaining the header's purpose. |

**`FollowUpList` (follow-up requests)**

| Attribute | Description |
|-----------|-------------|
| `Type` | Fixed to `FollowUpRequest`. |
| `Name` | On the parent parameter, an ID is generated automatically. On child parameters, the name of the follow-up request setting. |
| `Value` | The value of the follow-up request setting. |

### Authentication settings

| Setting | Description |
|---------|-------------|
| `AuthMethod` | The authentication method. `none`: no authentication, or the CRM/Helpdesk only needs plain variables (such as an API key or webhook URL) to exchange data. `basic`: credentials (username/password or an API key) are base64-encoded and sent in a header on every request. `oauth2`: token-based access without sharing credentials; tokens and other parameters are obtained through dedicated API requests. `bearertoken`: every request carries an `Authorization: Bearer {{.AccessToken}}` header, where `{{.AccessToken}}` is the token issued by the CRM/Helpdesk. |
| `AuthMode` | Authorization mode, for `oauth2` only. `authorization_code`: the standard flow, use it when the CRM/Helpdesk expects a `client_secret`. `pkce`: Authorization Code with PKCE (Proof Key for Code Exchange), use it when the CRM/Helpdesk supports PKCE for an extra layer of security. In PKCE, Cloud Voice generates a `code_verifier`, hashes it with SHA256 and Base64URL-encodes it into a `code_challenge` that it sends up front. It keeps the `code_verifier` locally and presents it during token exchange; the server hashes the submitted verifier the same way and compares it to the stored challenge. A match proves Cloud Voice holds the original verifier, so only that client can exchange the code for a token, which blocks interception attacks. |
| `AuthEndPoint` | The CRM/Helpdesk authorization URL opened to start the authorization flow. `oauth2` only. |
| `TokenEndPoint` | The CRM/Helpdesk URL that issues the access and refresh tokens. `oauth2` and `bearertoken` only. |
| `ContentType` | The content type of the token-retrieval request: `application/json` or `application/x-www-form-urlencoded`. |
| `CodeChallengeMethod` | How the `code_verifier` becomes the `code_challenge`. `S256`: SHA256 hash then Base64URL encode (recommended). `plain`: use the verifier as-is, for systems without SHA256 support. Available when `AuthMode` is `pkce`. |
| `AdditionalQueryString` | Query variables to add when the CRM/Helpdesk authorizes by query parameters rather than scope. `oauth2` only. |
| `Scope` | The scope of CRM/Helpdesk data Cloud Voice is permitted to access. `oauth2` only. |
| `CredentialType` | The credential type: `username_password` or `api_key`. `basic` only. |
| `Base64EncodedCredential` | The format used to build the basic-auth string from credential variables, for example `{{.username}}:{{.password}}` or `{{.api_key}}`. `basic` only. |
| `TokenRefreshEndpointMethod` | The HTTP method for the token-refresh request: `get` or `post`. `oauth2` and `bearertoken` only. |
| `TokenRefreshEndpoint` | The URL used to refresh the access token. `oauth2` and `bearertoken` only. |
| `TokenRefreshContentType` | The content type of the refresh request: `application/json`, `application/x-www-form-urlencoded`, or `multipart/form-data`. `oauth2` and `bearertoken` only. |
| `TokenRefreshInterval` | How often the token is refreshed automatically, in minutes. `oauth2` and `bearertoken` only. |
| `TokenRefreshBody` | The request body for the token-refresh request. `oauth2` and `bearertoken` only. |
| `EnableKeepalive` | Whether to send keep-alive requests: `0` = off, `1` = on (sent at the interval below). |
| `KeepaliveInterval` | How often keep-alive requests are sent, in minutes. |

### Follow-up request settings

| Setting | Description |
|---------|-------------|
| `TriggeredEvent` | The event that fires the follow-up request. `token_retrieved`: after an access token is obtained. `token_refreshed`: after an access token is refreshed. |
| `RequestMethod` | The HTTP method: `get` or `post`. |
| `Url` | The endpoint for the follow-up call, for example `https://api.example.com/rest-services/login`. |
| `Headers` | Request headers as JSON, with `{{.varname}}` for dynamic values, for example `{"Content-Type":"application/json", "X-Custom-Header": "{{.DynamicValue}}"}`. |
| `Body` | Request body as JSON, with `{{.varname}}` for dynamic values, for example `{"lastName":"{{.LastName}}","ownerId":"{{.Id}}","phone":"{{.BusinessNumber}}"}`. |
| `ResponseFieldPath` | The JSON path(s) that extract data from the follow-up response. Separate multiple paths with commas, for example `.data.access_token, .tokens[0].value`. |
| `TargetVariable` | The system variable name(s) that store the extracted values, existing or new, and available globally throughout the integration. Separate names with commas, for example `token,refresh`. Values are assigned in the same order as the paths in `ResponseFieldPath`. |

## User association scenario

This scenario pulls the list of users from the CRM/Helpdesk.

```xml
<Scenario Id="UserAssociation" Type="REST">
  <Parameters></Parameters>
  <Requests>
    <Request Name="UserAssociation" Method="GET" ResponseType="application/json" RequestEncoding="" URLFormat="https://www.api.example.com/v1/users?type=ActiveUsers">
      <Parameters>
        <Parameter Name="PaginationEnabled" Value="0" />
        <Parameter Name="PaginationType" Value="" />
        <Parameter Name="VarPageName" Value="page" />
        <Parameter Name="VarPageValue" Value="1" />
        <Parameter Name="VarPageSizeName" Value="page_size" />
        <Parameter Name="VarPageSizeValue" Value="10" />
      </Parameters>
      <Outputs>
        <Output Name="UserUniqueId" Path="users.#.id" Type=""></Output>
        <Output Name="FirstName" Path="users.#.First_Name" Type=""></Output>
        <Output Name="LastName" Path="users.#.Last_Name" Type=""></Output>
        <Output Name="Email" Path="users.#.Email" Type=""></Output>
      </Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `UserAssociation`. |
| `Type` | Fixed to `REST`, the scenario makes an HTTP request. |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request within the scenario. Fixed to `UserAssociation`. |
| `Method` | The HTTP method. Defaults to `GET`; change it if you need to. |
| `ResponseType` | The expected response format, JSON (`application/json`). |
| `RequestEncoding` | How the request is encoded. Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Parameter element (pagination)

The `Name`/`Value` parameters here configure pagination.

| Setting | Description |
|---------|-------------|
| `PaginationEnabled` | Whether pagination is on: `0` = off, `1` = on. |
| `PaginationType` | The pagination mode. `page_based`: by page number and page size. `offset_based`: by a starting index and a record limit. `link_based`: by following a "next page" URL in the response. |
| `VarPageName` | The request parameter that carries the page number. `page_based` only. |
| `VarPageValue` | The page number to start from. `page_based` only. |
| `VarPageSizeName` | The request parameter that carries the records-per-page count. `page_based` only. |
| `VarPageSizeValue` | The maximum records to return per page. `page_based` only. |
| `VarOffsetName` | The request parameter that carries the start position. `offset_based` only. |
| `VarOffsetValue` | How many records to skip before retrieving. `1` starts at the first record; `100` starts at the 100th. `offset_based` only. |
| `VarLimitName` | The request parameter that carries the records-per-page count. `offset_based` only. |
| `VarLimitValue` | The maximum records to return per page. `offset_based` only. |
| `VarNextPagePath` | The JSON path to the next-page link, for example `links.next`. `link_based` only. |

### Output element

| Attribute | Description |
|-----------|-------------|
| `Name` | The output variable pulled from the response. |
| `Path` | The location of the field in the response, using path syntax for nested data, for example `users.#.id`. |
| `Type` | The variable's data type. Fixed to `string`. |

**Variables**

| Variable | Description |
|----------|-------------|
| `UserUniqueId` | The CRM/Helpdesk user's unique ID. |
| `FirstName` | The user's first name. |
| `LastName` | The user's last name. |
| `Email` | The user's email address. |

## Automatic contact synchronization scenario

This scenario searches the CRM/Helpdesk for contacts. The results power contact search, automatic contact syncing, and call pop-ups (the window that appears with the caller's details when a call comes in).

:::caution
At least one phone number field must be enabled and returned (for example `BusinessNumber`). A template that reads no phone number cannot match callers to contacts, so contact sync and call pop-ups will not work.
:::

```xml
<Scenario Id="SyncContactAuto" Type="REST">
  <Presets></Presets>
  <Parameters>
    <Parameter Name="ContactUrlType" Value="retrieve_from_contact"></Parameter>
    <Parameter Name="URLFormat"></Parameter>
    <Parameter Name="ContactFieldForUri" Value="data.#.contactUrl"></Parameter>
    <Parameter Name="ContactsIdEnable" Value="1"></Parameter>
    <Parameter Name="FirstNameEnable" Value="1"></Parameter>
    <Parameter Name="BusinessNumberEnable" Value="1"></Parameter>
    <Parameter Name="CustomValueEnable" Value="0"></Parameter>
  </Parameters>
  <Requests>
    <Request Name="Contacts" Method="GET" ResponseType="application/json" RequestEncoding="" URLFormat="https://www.api.example.com/v1/Contacts/search?criteria=((Phone:equals:{{.Phone}})or(Mobile:equals:{{.Phone}}))">
      <Parameters></Parameters>
      <Outputs>
        <Output Name="ContactsId" Path="data.0.id" Type=""></Output>
        <Output Name="FirstName" Path="data.0.First_Name" Type=""></Output>
        <Output Name="BusinessNumber" Path="data.0.Phone" Type=""></Output>
        ...
        <Output Name="CustomValue" Path="data.0.Owner" Type=""></Output>
      </Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `SyncContactAuto`. |
| `Type` | Fixed to `REST`. |

### Parameter element (configuration)

| Setting | Description |
|---------|-------------|
| `ContactUrlType` | How the contact URL for the call pop-up is built. `specify_url_format`: construct it from a URL format, using variables. `retrieve_from_contact`: read it straight from a field in the contact-search response. |
| `URLFormat` | The contact-URL expression. You can build it from the variables captured during authentication, plus `ContactSyncType` (the contact type, taken from the search request name), `ContactId` (from this scenario's response), and `CustomValue` (a custom field from the response). For example: `{{.crm_url}}/crm/{{.CustomValue}}/tab/{{Capitalize .ContactSyncType}}/{{.ContactId}}`. If the available variables aren't enough, add requests to fetch what you need, see [Retrieve additional variables](#retrieve-additional-variables-for-global-use). |
| `ContactFieldForUri` | The JSON path to the contact-URL field in the response, for example `.data.#.contactUrl`. |
| `ContactsIdEnable` | Whether to read the contact's ID from the response. Set to `1`. |
| `FirstNameEnable` | Whether to read the contact's first name. Set to `1`. |
| `LastNameEnable` | Whether to read the contact's last name: `0` = no, `1` = yes. |
| `CompanyEnable` | Whether to read the contact's company: `0` = no, `1` = yes. |
| `EmailEnable` | Whether to read the contact's email: `0` = no, `1` = yes. |
| `BusinessNumberEnable` | Whether to read the business phone number: `0` = no, `1` = yes. At least one phone number is required. |
| `BusinessNumber2Enable` | Whether to read a second business number: `0` = no, `1` = yes. |
| `BusinessFaxNumberEnable` | Whether to read the business fax number: `0` = no, `1` = yes. |
| `MobileNumberEnable` | Whether to read the mobile number: `0` = no, `1` = yes. |
| `MobileNumber2Enable` | Whether to read a second mobile number: `0` = no, `1` = yes. |
| `HomeNumberEnable` | Whether to read the home number: `0` = no, `1` = yes. |
| `HomeNumber2Enable` | Whether to read a second home number: `0` = no, `1` = yes. |
| `HomeFaxNumberEnable` | Whether to read the home fax number: `0` = no, `1` = yes. |
| `OtherNumberEnable` | Whether to read any other number type: `0` = no, `1` = yes. |
| `ZipCodeEnable` | Whether to read the zip code: `0` = no, `1` = yes. |
| `StreetEnable` | Whether to read the street: `0` = no, `1` = yes. |
| `CityEnable` | Whether to read the city: `0` = no, `1` = yes. |
| `StateEnable` | Whether to read the state/province: `0` = no, `1` = yes. |
| `CountryEnable` | Whether to read the country: `0` = no, `1` = yes. |
| `RemarkEnable` | Whether to read the contact's remark: `0` = no, `1` = yes. |
| `CustomValueEnable` | Whether to enable a custom variable used to build the contact URL: `0` = off, `1` = on. |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request. Set it to the actual name of the contact type being searched in the CRM/Helpdesk; it becomes the `ContactSyncType` variable. |
| `Method` | The HTTP method. Defaults to `GET`; change it if needed. |
| `ResponseType` | JSON (`application/json`). |
| `RequestEncoding` | Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Output element

| Attribute | Description |
|-----------|-------------|
| `Name` | The output variable to pull from the response. |
| `Path` | The field's location, for example `users.#.id`. |
| `Type` | Fixed to `string`. |

**Variables**

:::note
Values retrieved from a call can be referenced across modules for the whole duration of that call, until it ends.
:::

| Variable | Description |
|----------|-------------|
| `ContactsId` | **(Required)** The contact's unique ID. |
| `FirstName` | **(Required)** The contact's first name. |
| `LastName` | The contact's last name. |
| `Company` | The contact's company. |
| `Email` | The contact's email. |
| `BusinessNumber` | The business phone number. At least one phone number is required. |
| `BusinessNumber2` | A second business number. |
| `BusinessFaxNumber` | The business fax number. |
| `MobileNumber` | The mobile number. |
| `MobileNumber2` | A second mobile number. |
| `HomeNumber` | The home number. |
| `HomeNumber2` | A second home number. |
| `HomeFaxNumber` | The home fax number. |
| `OtherNumber` | Any other phone number. |
| `ZipCode` | Zip code. |
| `Street` | Street. |
| `City` | City. |
| `State` | State or province. |
| `Country` | Country. |
| `Remark` | Remark. |
| `CustomValue` | A custom variable used to build the contact URL. |

## Automatic contact creation scenario

This scenario creates a new contact in the CRM/Helpdesk when a caller's number doesn't match any existing record.

```xml
<Scenario Id="CreateNewContact" Type="REST">
  <Parameters></Parameters>
  <Requests>
    <Request Name="Contacts" Method="POST" ResponseType="application/json" RequestEncoding="" URLFormat="https://www.api.example.com/v1/Contacts">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value='{"data": [{"Last_Name":"{{.LastName}}","First_Name":"{{.FirstName}}","Phone":"{{.BusinessNumber}}"}]}'></Parameter>
      </Parameters>
      <Outputs></Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `CreateNewContact`. |
| `Type` | Fixed to `REST`. |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request. Set it to the actual name of the contact type being created in the CRM/Helpdesk. |
| `Method` | `POST`. |
| `ResponseType` | JSON (`application/json`). |
| `RequestEncoding` | Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Parameter element (request body)

The `<Parameter>` nested inside `<Request>` defines the request body.

| Attribute | Description |
|-----------|-------------|
| `Name` | Fixed to `Data`. |
| `Type` | Fixed to `Body`. |
| `Value` | The parameters to send in the body, wrapped in a `data` structure. Values can come from Cloud Voice's built-in variables. |

:::note
The value must follow XML rules. If you need a line break inside it, write the escape sequence `&#xA;` for a newline.
:::

**Variables** (required only, for anything more, see [Retrieve additional variables](#retrieve-additional-variables-for-global-use)):

| Variable | Description |
|----------|-------------|
| Variables from the `AuthMethod` scenario | The credential values captured during authentication. |
| Target variables from follow-up requests | Values extracted from follow-up request responses. |
| `{{.LastName}}` | The contact's last name. |
| `{{.FirstName}}` | The contact's first name. |
| `{{.BusinessNumber}}` | The contact's phone number. |

## Automatic ticket creation scenario (Helpdesk only)

This scenario opens a new ticket in the Helpdesk.

```xml
<Scenario Id="CreateNewTicket" Type="REST">
  <Presets></Presets>
  <Parameters>
    <Parameter Name="EnableSubject" Value="1"></Parameter>
    <Parameter Name="Subject" Value="{{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}}"></Parameter>
    <Parameter Name="EnableDescription" Value="1"></Parameter>
    <Parameter Name="Description" Value="{{.Time}} {{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}} {{.Talk_Duration}}"></Parameter>
  </Parameters>
  <Requests>
    <Request Name="CreateNewTicket" Method="POST" Weight="0" ResponseType="application/json" RequestEncoding="" URLFormat="https://{{.domain}}/api/v1/tickets">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value='{"subject":"{{.Subject}}","contactId":"{{.ContactId}}","phone":"{{.ContactNumber}}","description":"{{.Description}}"}'></Parameter>
      </Parameters>
      <Outputs></Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `CreateNewTicket`. |
| `Type` | Fixed to `REST`. |

### Parameter element (configuration)

| Setting | Description |
|---------|-------------|
| `EnableSubject` | Whether users can customize the ticket subject: `0` = off, `1` = on. |
| `Subject` | The default subject. Defaults to `{{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}}`. See [Call variables](#call-variables) for what you can use. |
| `EnableDescription` | Whether users can customize the ticket description: `0` = off, `1` = on. |
| `Description` | The default description. Defaults to `{{.Time}} {{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}} {{.Talk_Duration}}`. See [Call variables](#call-variables). |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request. Fixed to `CreateNewTicket`. |
| `Method` | `POST`. |
| `ResponseType` | JSON (`application/json`). |
| `RequestEncoding` | Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Parameter element (request body)

| Attribute | Description |
|-----------|-------------|
| `Name` | Fixed to `Data`. |
| `Type` | Fixed to `Body`. |
| `Value` | The parameters to send in the body. Values can come from Cloud Voice's built-in variables. |

:::note
The value must follow XML rules, use `&#xA;` where a newline is needed.
:::

The body accepts the variables listed under [Call variables](#call-variables).

## Call journal scenario

This scenario logs the call activity of associated users back to the CRM/Helpdesk. It defines both a creation request and an update request.

```xml
<Scenario Id="CallJournal" Type="REST">
  <Presets></Presets>
  <Parameters>
    <Parameter Name="EnableSubject" Value="1"></Parameter>
    <Parameter Name="Subject" Value="Extension Call"></Parameter>
    <Parameter Name="EnableDescription" Value="1"></Parameter>
    <Parameter Name="Description" Value="Call: {{.Time}} {{.Call_Log_Status}} from {{.Call_From}} to {{.Call_To}} {{.Talk_Duration}}"></Parameter>
    <Parameter Name="EnablePlayCallRecording" Value="1"></Parameter>
    <Parameter Name="PlayCallRecording" Value="0"></Parameter>
    <Parameter Name="EnableForwardCallLogForAnsweredAgent" Value="0"></Parameter>
    <Parameter Name="ForwardCallLogForAnsweredAgent" Value="0"></Parameter>
  </Parameters>
  <Requests>
    <Request Name="CallJournal" Method="POST" Weight="0" ResponseType="application/json" URLFormat="https://www.api.example.com/v2/Calls">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value="..."></Parameter>
      </Parameters>
      <Outputs></Outputs>
    </Request>
    <Request Name="CallJournalUpdate" Method="PUT" Weight="0" ResponseType="application/json" URLFormat="https://www.api.example.com/v2/Calls/{{.CallId}}">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value="..."></Parameter>
      </Parameters>
      <Outputs></Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `CallJournal`. |
| `Type` | Fixed to `REST`. |

### Parameter element (configuration)

| Setting | Description |
|---------|-------------|
| `EnableSubject` | Whether the call-log subject can be configured in the integration: `0` = off, `1` = on. |
| `Subject` | The default subject. Defaults to `Extension Call`; you can also build it from [Call variables](#call-variables). |
| `EnableDescription` | Whether the call-log description can be configured: `0` = off, `1` = on. |
| `Description` | The default description. See [Call variables](#call-variables) for what you can use. |
| `EnablePlayCallRecording` | Whether the "play recordings inside the CRM/Helpdesk" option is configurable: `0` = off, `1` = on. |
| `PlayCallRecording` | The default state of recording playback: `0` = off, `1` = on. |
| `EnableForwardCallLogForAnsweredAgent` | Whether the option below is configurable in the integration. |
| `ForwardCallLogForAnsweredAgent` | Default state of the option that suppresses missed-call logs for queue and ring-group calls sent to non-answering agents. `0` = off. `1` = on: the call log syncs only to the agent who answered, and missed-call entries for that same call are not synced to agents who didn't answer. |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request. `CallJournal`: creates a new call log. `CallJournalUpdate`: updates an existing log with extra detail. |
| `Method` | `POST` or `PUT`. |
| `ResponseType` | JSON (`application/json`). |
| `RequestEncoding` | Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Parameter element (request body)

| Attribute | Description |
|-----------|-------------|
| `Name` | Fixed to `Data`. |
| `Type` | Fixed to `Body`. |
| `Value` | The body parameters, drawn from Cloud Voice's built-in variables. |

:::note
The value must follow XML rules, use `&#xA;` for newlines. Because the body is JSON inside an XML attribute, inner double quotes are written as `&#34;`. For example:

```text
{&#xA;  &#34;data&#34;: [{&#xA;    &#34;Description&#34;: &#34;{{.Description}}&#34;,&#xA;    &#34;Call_Duration&#34;: &#34;{{.Talk_Duration_Sec}}&#34;&#xA;  }]&#xA;}
```
:::

Alongside the general [Call variables](#call-variables), the call journal can also use:

| Variable | Description |
|----------|-------------|
| `{{.EnableCallRecording}}` | Whether call recording is enabled: `0` = disabled, `1` = enabled. |
| `{{.AI_Transcription}}` | The AI-generated call transcript. |
| `{{.AI_Summary}}` | The AI-generated call summary. |
| `{{.Call_Note}}` | The call note content. |

## Call variables

The ticket-creation and call-journal scenarios share the following variable set. Use these when building a `Subject`, `Description`, or request body.

| Variable | Description |
|----------|-------------|
| Variables from the `AuthMethod` scenario | Credential values captured during authentication. |
| Target variables from follow-up requests | Values extracted from follow-up request responses. |
| `{{.Subject}}` | The subject line, taken from the scenario's `Subject` parameter. |
| `{{.Description}}` | The description, taken from the scenario's `Description` parameter. |
| `{{.LinkedId}}` | The call's unique ID. |
| `{{.Time}}` | When the call was made or received, in Cloud Voice's time format. |
| `{{.StartTimeUnix}}` | The Unix timestamp of the call start. |
| `{{.EndTimeUnix}}` | The Unix timestamp of the call end. |
| `{{.Call_From}}` | The calling party's name and number, formatted as `Caller's name <Caller's number>`. |
| `{{.Call_To}}` | The called party's name and number, in the same `name <number>` format. |
| `{{.CallerName}}` | The caller's name. |
| `{{.CallerNumber}}` | The caller's number. |
| `{{.CalleeName}}` | The callee's name. |
| `{{.CalleeNumber}}` | The callee's number. |
| `{{.CrmId}}` | The CRM/Helpdesk user ID linked to a Cloud Voice extension. |
| `{{.ExtensionFirstName}}` | The extension user's first name. |
| `{{.ExtensionLastName}}` | The extension user's last name. |
| `{{.ExtensionEmail}}` | The extension user's email. |
| `{{.ContactSyncType}}` | The contact type. |
| `{{.ContactNumber}}` | The contact's number. |
| `{{.ContactId}}` | The contact's unique ID. |
| `{{.TicketId}}` | The ID of the ticket created from a call. Retrieving it takes extra template settings, see [Retrieve a ticket ID](#retrieve-a-ticket-id-for-further-operations). |
| `{{.CallDuration}}` | The elapsed time from call start to call end. |
| `{{.Talk_Duration}}` | The elapsed time from answer to hang-up, formatted `hh:mm:ss`. |
| `{{.Talk_Duration_Sec}}` | The talk time in seconds. |
| `{{.Communication_Type}}` | Call direction: `Inbound` or `Outbound`. |
| `{{.Call_Status}}` | Processing status: `Missed` (unanswered) or `Completed` (connected and finished). |
| `{{.Call_Log_Status}}` | Call status: `Missed Call`, `Outgoing Call`, `Incoming Call`, or `Voicemail`. |
| `{{.CallDisposition}}` | Call disposition: `MISSED`, `VOICEMAIL`, `BUSY`, `ANSWERED`, or `NO ANSWER`. |

## Chat journal scenario

This scenario syncs chat messages between associated users and contacts to the CRM/Helpdesk.

```xml
<Scenario Id="ChatJournal" Type="REST">
  <Presets></Presets>
  <Parameters>
    <Parameter Name="EnableSubject" Value="1" />
    <Parameter Name="Subject" Value="PhoneSystem External Chat Session" />
    <Parameter Name="EnableCreateType" Value="0" />
    <Parameter Name="CreateType" Value="" />
  </Parameters>
  <Requests>
    <Request Name="ChatJournalDefault" Method="POST" Weight="0" ResponseType="application/json" URLFormat="https://www.api.example.com/crm/v7/Tasks">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value="..." />
      </Parameters>
      <Outputs />
    </Request>
  </Requests>
</Scenario>
```

### Scenario element

| Attribute | Description |
|-----------|-------------|
| `Id` | Fixed to `ChatJournal`. |
| `Type` | Fixed to `REST`. |

### Parameter element (configuration)

| Setting | Description |
|---------|-------------|
| `EnableSubject` | Whether the synced record's subject is configurable: `0` = off, `1` = on. |
| `Subject` | The default subject. Defaults to `PhoneSystem External Chat Session`; you can also build it from the variables below. |
| `EnableCreateType` | Reserved; not currently used. |
| `CreateType` | Reserved; not currently used. |

### Request element

| Attribute | Description |
|-----------|-------------|
| `Name` | Identifies the request. Fixed to `ChatJournalDefault`. |
| `Method` | `POST` or `PUT`. |
| `ResponseType` | JSON (`application/json`). |
| `RequestEncoding` | Empty in this scenario. |
| `URLFormat` | The API endpoint URL. |

### Parameter element (request body)

| Attribute | Description |
|-----------|-------------|
| `Name` | Fixed to `Data`. |
| `Type` | Fixed to `Body`. |
| `Value` | The body parameters, drawn from Cloud Voice's built-in variables. Use `&#xA;` for newlines. |

**Variables**

| Variable | Description |
|----------|-------------|
| Variables from the `AuthMethod` scenario | Credential values captured during authentication. |
| Target variables from follow-up requests | Values extracted from follow-up request responses. |
| `{{.ContactNumber}}` | The contact's phone number. |
| `{{.ContactEmail}}` | The contact's email address. |
| `{{.ContactName}}` | The contact's name. |
| `{{.ContactEntityId}}` | The entity ID of the matched contact, lead, or account. |
| `{{.ContactEntityType}}` | The type of the matched entity (contact, lead, or account). |
| `{{.QueueName}}` | The message queue's name, included when the chat is routed to a queue. |
| `{{.Messages}}` | The messages exchanged during the session, times, senders, and content. |
| `{{.ExtensionNumber}}` | The extension of the agent who handled the chat or closed the session. If the system closed it automatically, this is `PBX System`. |
| `{{.ExtensionFirstName}}` | The first name of that extension or agent. If auto-closed, this is `PBX System`. |
| `{{.ExtensionLastName}}` | The last name of that extension or agent. If auto-closed, this is `PBX System`. |
| `{{.ExtensionEmail}}` | The email of the extension or agent who handled the chat. |
| `{{.ChatDuration}}` | The session length in `hh:mm:ss`. To get total minutes: `{{ToMinutes .ChatDuration}}`. |
| `{{.StartTimeUnix}}` | The Unix timestamp (seconds) of the session start. Format as local time with `{{ TimeFormat .StartTimeUnix "yyyy-MM-ddTHH:mm:ss.000Zz" "0" }}`, as UTC with `"1"`, or to milliseconds with `{{ToMillis .StartTimeUnix}}`. |
| `{{.EndTimeUnix}}` | The Unix timestamp (seconds) of the session end, formatted the same way as `{{.StartTimeUnix}}`. |

## Extended configurations

Beyond the scenarios you set up on the configuration page, you can hand-edit the template to add supplementary behavior.

:::note
Custom edits you make directly in the template are preserved, changes made later through the Cloud Voice web portal won't overwrite them.
:::

### Set custom request headers

To add custom headers, include one or more `<Parameter>` elements with `Type` set to `Header`. In the example below, an `X-Auth-Token` header carries the API key: `Father` (fixed to `PopulateTemplateString`) groups the related parameters, `Type` (fixed to `Header`) marks it as a header, and `Name`/`Value` supply the header name and value, producing `X-Auth-Token:{{.api_key}}` on the request.

```xml
<Requests>
  <Request Name="contacts" Method="GET" ResponseType="application/json" URLFormat="https://api.example.com/contacts/search?number={{.Phone}}">
    <Parameters>
      <Parameter Father="PopulateTemplateString" Name="X-Auth-Token" Type="Header" Value="{{.api_key}}" />
    </Parameters>
    <Outputs>
      ...
    </Outputs>
  </Request>
</Requests>
```

### Identify token errors

In the `AuthMethod` scenario, add a `TokenInvalid` parameter to tell token problems apart from other failures. Set its `Value` to the token-related error code or response text you expect. If a response returns a status other than `200` and its body contains that value, the failure is flagged as **TokenInvalid**.

```xml
<Scenario Id="AuthMethod" Type="AUTH">
  <Presets />
  <Parameters>
    <Parameter Name="AuthMethod" Value="oauth2" />
    ...
    <Parameter Father="TokenErrorMap" Type="TokenInvalid" Name="TokenInvalid" Value="INVALID_TOKEN" />
    ...
  </Parameters>
  <Requests />
  <Responses />
</Scenario>
```

### Retrieve additional variables for global use

When you need values that aren't provided out of the box, or want common data available throughout the integration, define a `GetGlobalInfo` scenario with requests that fetch them. These requests run when the integration finishes or Cloud Voice starts. The values land in `Output` elements whose names become the variable names, and they can then be referenced from other scenarios (except the authentication scenario).

```xml
<Scenario Id="GetGlobalInfo" Type="REST">
  <Presets />
  <Parameters />
  <Requests>
    <Request Name="GetDepartments" Method="GET" ResponseType="application/json" URLFormat="https://desk.example.{{.domain_suffix}}/api/v1/departments">
      <Parameters />
      <Outputs>
        <Output Name="DepartmentId" Path="data.#.id" />
      </Outputs>
    </Request>
    <Request Name="GetOrganizations" Method="GET" ResponseType="application/json" URLFormat="https://desk.example.{{.domain_suffix}}/api/v1/organizations">
      <Parameters />
      <Outputs>
        <Output Name="PortalName" Path="data.#(portalName!=&quot;&quot;).portalName" />
      </Outputs>
    </Request>
  </Requests>
</Scenario>
```

### Supplement contact query information

If your first contact query doesn't return everything you need, you can run a follow-on query with the returned contact ID (or other returned data). In the example below, the initial sync request leaves the extra phone-number fields empty:

```xml
<Scenario Id="SyncContactAuto" Type="REST">
  <Presets />
  <Parameters>
    <Parameter Name="ContactUrlType" Value="specify_url_format" />
    ...
  </Parameters>
  <Requests>
    <Request Name="contacts" Method="GET" ResponseType="application/json" URLFormat="https://{{.subdomain}}.example.com/api/v2/users?query=phone:{{UrlEncode .Phone}}&amp;role[]=end-user">
      <Parameters />
      <Outputs Next="GetIdentities">
        <Output Name="ContactsId" Path="users.#.id" />
        <Output Name="FirstName" Path="users.#.name" />
        <Output Name="BusinessNumber" Path="users.#.phone" />
        <!-- these phone-number fields come back empty -->
        <Output Name="BusinessNumber2" Path=""></Output>
        <Output Name="MobileNumber" Path=""></Output>
        <Output Name="HomeNumber" Path=""></Output>
      </Outputs>
    </Request>
  </Requests>
</Scenario>
```

To fill in the missing numbers, chain a second scenario:

1. **Add a `Next` attribute to the original request.** On the initial request's `<Outputs>` element, set `Next` to the name of the request you'll add in the `Common` scenario, here, `GetIdentities`:

   ```xml
   <Outputs Next="GetIdentities">
   ```

2. **Create a `Common` scenario.** Add a scenario named `Common` with type `REST` (both fixed), then add the `GetIdentities` request. It uses `{{.ContactsId}}` from the first request to look up the extra details:

   ```xml
   <Scenario Id="Common" Type="REST">
     <Presets></Presets>
     <Parameters></Parameters>
     <Requests>
       <Request Name="GetIdentities" Method="GET" ResponseType="application/json" URLFormat="https://{{.subdomain}}.example.com/api/v2/users/{{.ContactsId}}/identities">
         <Parameters></Parameters>
         <Outputs>
           <Output Name="BusinessNumber2" Path="identities.#(type==&quot;phone_number&quot;)#|1.value"></Output>
           <Output Name="MobileNumber" Path="identities.#(type==&quot;phone_number&quot;)#|3.value"></Output>
           <Output Name="HomeNumber" Path="identities.#(type==&quot;phone_number&quot;)#|5.value"></Output>
         </Outputs>
       </Request>
     </Requests>
   </Scenario>
   ```

Because the original scenario references the request through `Next`, the variable from the first query is passed along. The `GetIdentities` request runs and backfills its `Outputs` into the original response to complete the record.

### Retrieve a ticket ID for further operations

In a Helpdesk template you can capture the ticket ID so you can act on the ticket later, for example, updating it or referencing it in a call journal. This is useful when a ticket is created early (as the phone rings) and is missing information you'll only have once the call finishes.

```xml
<Scenario Id="CreateNewTicket" Type="REST">
  <Presets />
  <Parameters>
    <Parameter Name="EnableSubject" Value="1" />
    ...
    <Parameter Name="NeedSyncContact" Value="1" />
  </Parameters>
  <Requests>
    <Request Name="CreateNewTicket" Method="POST" ResponseType="application/json" URLFormat="https://{{.domain}}/api/v1/tickets">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value='{"departmentId":"{{.DepartmentId}}","subject":"{{.Subject}}","contactId":"{{.ContactId}}","phone":"{{.ContactNumber}}","description":"{{.Description}}"}' />
      </Parameters>
      <Outputs>
        <Output Name="TicketId" Path="id" />
      </Outputs>
    </Request>
    <Request Name="UpdateTicket" Method="POST" ResponseType="application/json" URLFormat="https://{{.domain}}/api/v1/tickets/{{.TicketId}}/comments">
      <Parameters>
        <Parameter Name="Data" Type="Body" Value='{"isPublic":"true","content":"{{.Description}}"}' />
      </Parameters>
      <Outputs />
    </Request>
  </Requests>
</Scenario>
```

1. **Capture the ticket ID.** In the `CreateNewTicket` scenario, add an `<Output>` that reads the ID from the `CreateNewTicket` response, so Cloud Voice stores `TicketId` for later:

   ```xml
   <Outputs>
     <Output Name="TicketId" Path="id" />
   </Outputs>
   ```

2. **Update the ticket.** Add a request that updates the ticket for the matching call record, using the stored ID. The ticket is then filled out with everything gathered after it was first created.
