Skip to content

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.

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.

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:

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

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

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

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 transform or reformat a variable’s value inline. The template supports the following.

FunctionWhat it doesExample
TimeFormatReformats 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.
ToMillisConverts a timestamp in seconds to milliseconds.{{ ToMillis .StartTimeUnix }}, with 1672531199, returns 1672531199000.
CapitalizeCapitalizes the first letter of a string.{{ Capitalize .variable_string }}, with hello world, returns Hello world.
UrlEncodeURL-encodes a string.{{ UrlEncode .variable }}, with hello world!, returns hello%20world%21.

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

<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>
ElementPurpose
<Information>The root element. Its attributes carry the template’s basic details and feature switches (see 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

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

AttributeDescription
ProviderThe template type. Fixed to crm or helpdesk.
NameThe template’s display name.
KeyA unique identifier for the template.
LogoThe filename of the logo.
RemarkA free-text note describing the template.
VersionThe template version, for example 1.0.0.
AuthTypeThe authentication method: none, basic, oauth2, or bearertoken.
MaxConcurrentRequestThe maximum number of HTTP requests allowed to run against the CRM/Helpdesk at once.
UserAssociationWhether user association is on. 0 = off, 1 = on.
CallJournalWhether call journaling is on. 0 = off, 1 = on.
CreateNewContactWhether automatic contact creation is on. 0 = off, 1 = on.
CreateNewTicketWhether automatic ticket creation is on. 0 = off, 1 = on.
ChatJournalWhether chat journaling is on. 0 = off, 1 = on.

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

<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>
AttributeDescription
IdFixed to AuthMethod.
TypeFixed to AUTH, the scenario performs authentication.

Each <Parameter> uses these attributes:

AttributeDescription
NameThe name of the authentication setting.
ValueThe value of the authentication setting.
FatherGroups 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.

  • 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)

AttributeDescription
NameThe variable name of the field, referenceable in the template. Set it to client_id and you can use {{.client_id}}.
EditorThe field type: string (plain text), password (masked text), or list (choose from preset options).
TitleThe label shown above the field in the setup UI.
ValueThe preset options, used only when Editor is list. Separate options with commas, for example option1,option2.
IsRequiredWhether the field is mandatory: 0 = optional, 1 = required. Available when AuthMethod is oauth2.

PopulateTemplateString (custom HTTP headers)

AttributeDescription
TypeFixed to Header.
NameThe header name.
ValueThe header value, a literal string or a variable. You can reference a credential variable here, for example {{.client_id}}.
DescriptionA short note explaining the header’s purpose.

FollowUpList (follow-up requests)

AttributeDescription
TypeFixed to FollowUpRequest.
NameOn the parent parameter, an ID is generated automatically. On child parameters, the name of the follow-up request setting.
ValueThe value of the follow-up request setting.
SettingDescription
AuthMethodThe 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.
AuthModeAuthorization 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.
AuthEndPointThe CRM/Helpdesk authorization URL opened to start the authorization flow. oauth2 only.
TokenEndPointThe CRM/Helpdesk URL that issues the access and refresh tokens. oauth2 and bearertoken only.
ContentTypeThe content type of the token-retrieval request: application/json or application/x-www-form-urlencoded.
CodeChallengeMethodHow 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.
AdditionalQueryStringQuery variables to add when the CRM/Helpdesk authorizes by query parameters rather than scope. oauth2 only.
ScopeThe scope of CRM/Helpdesk data Cloud Voice is permitted to access. oauth2 only.
CredentialTypeThe credential type: username_password or api_key. basic only.
Base64EncodedCredentialThe format used to build the basic-auth string from credential variables, for example {{.username}}:{{.password}} or {{.api_key}}. basic only.
TokenRefreshEndpointMethodThe HTTP method for the token-refresh request: get or post. oauth2 and bearertoken only.
TokenRefreshEndpointThe URL used to refresh the access token. oauth2 and bearertoken only.
TokenRefreshContentTypeThe content type of the refresh request: application/json, application/x-www-form-urlencoded, or multipart/form-data. oauth2 and bearertoken only.
TokenRefreshIntervalHow often the token is refreshed automatically, in minutes. oauth2 and bearertoken only.
TokenRefreshBodyThe request body for the token-refresh request. oauth2 and bearertoken only.
EnableKeepaliveWhether to send keep-alive requests: 0 = off, 1 = on (sent at the interval below).
KeepaliveIntervalHow often keep-alive requests are sent, in minutes.
SettingDescription
TriggeredEventThe event that fires the follow-up request. token_retrieved: after an access token is obtained. token_refreshed: after an access token is refreshed.
RequestMethodThe HTTP method: get or post.
UrlThe endpoint for the follow-up call, for example https://api.example.com/rest-services/login.
HeadersRequest headers as JSON, with {{.varname}} for dynamic values, for example {"Content-Type":"application/json", "X-Custom-Header": "{{.DynamicValue}}"}.
BodyRequest body as JSON, with {{.varname}} for dynamic values, for example {"lastName":"{{.LastName}}","ownerId":"{{.Id}}","phone":"{{.BusinessNumber}}"}.
ResponseFieldPathThe JSON path(s) that extract data from the follow-up response. Separate multiple paths with commas, for example .data.access_token, .tokens[0].value.
TargetVariableThe 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.

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

<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>
AttributeDescription
IdFixed to UserAssociation.
TypeFixed to REST, the scenario makes an HTTP request.
AttributeDescription
NameIdentifies the request within the scenario. Fixed to UserAssociation.
MethodThe HTTP method. Defaults to GET; change it if you need to.
ResponseTypeThe expected response format, JSON (application/json).
RequestEncodingHow the request is encoded. Empty in this scenario.
URLFormatThe API endpoint URL.

The Name/Value parameters here configure pagination.

SettingDescription
PaginationEnabledWhether pagination is on: 0 = off, 1 = on.
PaginationTypeThe 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.
VarPageNameThe request parameter that carries the page number. page_based only.
VarPageValueThe page number to start from. page_based only.
VarPageSizeNameThe request parameter that carries the records-per-page count. page_based only.
VarPageSizeValueThe maximum records to return per page. page_based only.
VarOffsetNameThe request parameter that carries the start position. offset_based only.
VarOffsetValueHow many records to skip before retrieving. 1 starts at the first record; 100 starts at the 100th. offset_based only.
VarLimitNameThe request parameter that carries the records-per-page count. offset_based only.
VarLimitValueThe maximum records to return per page. offset_based only.
VarNextPagePathThe JSON path to the next-page link, for example links.next. link_based only.
AttributeDescription
NameThe output variable pulled from the response.
PathThe location of the field in the response, using path syntax for nested data, for example users.#.id.
TypeThe variable’s data type. Fixed to string.

Variables

VariableDescription
UserUniqueIdThe CRM/Helpdesk user’s unique ID.
FirstNameThe user’s first name.
LastNameThe user’s last name.
EmailThe user’s email address.

Automatic contact synchronization scenario

Section titled “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).

<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>
AttributeDescription
IdFixed to SyncContactAuto.
TypeFixed to REST.
SettingDescription
ContactUrlTypeHow 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.
URLFormatThe 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.
ContactFieldForUriThe JSON path to the contact-URL field in the response, for example .data.#.contactUrl.
ContactsIdEnableWhether to read the contact’s ID from the response. Set to 1.
FirstNameEnableWhether to read the contact’s first name. Set to 1.
LastNameEnableWhether to read the contact’s last name: 0 = no, 1 = yes.
CompanyEnableWhether to read the contact’s company: 0 = no, 1 = yes.
EmailEnableWhether to read the contact’s email: 0 = no, 1 = yes.
BusinessNumberEnableWhether to read the business phone number: 0 = no, 1 = yes. At least one phone number is required.
BusinessNumber2EnableWhether to read a second business number: 0 = no, 1 = yes.
BusinessFaxNumberEnableWhether to read the business fax number: 0 = no, 1 = yes.
MobileNumberEnableWhether to read the mobile number: 0 = no, 1 = yes.
MobileNumber2EnableWhether to read a second mobile number: 0 = no, 1 = yes.
HomeNumberEnableWhether to read the home number: 0 = no, 1 = yes.
HomeNumber2EnableWhether to read a second home number: 0 = no, 1 = yes.
HomeFaxNumberEnableWhether to read the home fax number: 0 = no, 1 = yes.
OtherNumberEnableWhether to read any other number type: 0 = no, 1 = yes.
ZipCodeEnableWhether to read the zip code: 0 = no, 1 = yes.
StreetEnableWhether to read the street: 0 = no, 1 = yes.
CityEnableWhether to read the city: 0 = no, 1 = yes.
StateEnableWhether to read the state/province: 0 = no, 1 = yes.
CountryEnableWhether to read the country: 0 = no, 1 = yes.
RemarkEnableWhether to read the contact’s remark: 0 = no, 1 = yes.
CustomValueEnableWhether to enable a custom variable used to build the contact URL: 0 = off, 1 = on.
AttributeDescription
NameIdentifies the request. Set it to the actual name of the contact type being searched in the CRM/Helpdesk; it becomes the ContactSyncType variable.
MethodThe HTTP method. Defaults to GET; change it if needed.
ResponseTypeJSON (application/json).
RequestEncodingEmpty in this scenario.
URLFormatThe API endpoint URL.
AttributeDescription
NameThe output variable to pull from the response.
PathThe field’s location, for example users.#.id.
TypeFixed to string.

Variables

VariableDescription
ContactsId(Required) The contact’s unique ID.
FirstName(Required) The contact’s first name.
LastNameThe contact’s last name.
CompanyThe contact’s company.
EmailThe contact’s email.
BusinessNumberThe business phone number. At least one phone number is required.
BusinessNumber2A second business number.
BusinessFaxNumberThe business fax number.
MobileNumberThe mobile number.
MobileNumber2A second mobile number.
HomeNumberThe home number.
HomeNumber2A second home number.
HomeFaxNumberThe home fax number.
OtherNumberAny other phone number.
ZipCodeZip code.
StreetStreet.
CityCity.
StateState or province.
CountryCountry.
RemarkRemark.
CustomValueA custom variable used to build the contact URL.

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

<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>
AttributeDescription
IdFixed to CreateNewContact.
TypeFixed to REST.
AttributeDescription
NameIdentifies the request. Set it to the actual name of the contact type being created in the CRM/Helpdesk.
MethodPOST.
ResponseTypeJSON (application/json).
RequestEncodingEmpty in this scenario.
URLFormatThe API endpoint URL.

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

AttributeDescription
NameFixed to Data.
TypeFixed to Body.
ValueThe parameters to send in the body, wrapped in a data structure. Values can come from Cloud Voice’s built-in variables.

Variables (required only, for anything more, see Retrieve additional variables):

VariableDescription
Variables from the AuthMethod scenarioThe credential values captured during authentication.
Target variables from follow-up requestsValues 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)

Section titled “Automatic ticket creation scenario (Helpdesk only)”

This scenario opens a new ticket in the Helpdesk.

<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>
AttributeDescription
IdFixed to CreateNewTicket.
TypeFixed to REST.
SettingDescription
EnableSubjectWhether users can customize the ticket subject: 0 = off, 1 = on.
SubjectThe default subject. Defaults to {{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}}. See Call variables for what you can use.
EnableDescriptionWhether users can customize the ticket description: 0 = off, 1 = on.
DescriptionThe default description. Defaults to {{.Time}} {{.Communication_Type}} {{.Call_Status}} - from {{.Call_From}} to {{.Call_To}} {{.Talk_Duration}}. See Call variables.
AttributeDescription
NameIdentifies the request. Fixed to CreateNewTicket.
MethodPOST.
ResponseTypeJSON (application/json).
RequestEncodingEmpty in this scenario.
URLFormatThe API endpoint URL.
AttributeDescription
NameFixed to Data.
TypeFixed to Body.
ValueThe parameters to send in the body. Values can come from Cloud Voice’s built-in variables.

The body accepts the variables listed under Call variables.

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

<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>
AttributeDescription
IdFixed to CallJournal.
TypeFixed to REST.
SettingDescription
EnableSubjectWhether the call-log subject can be configured in the integration: 0 = off, 1 = on.
SubjectThe default subject. Defaults to Extension Call; you can also build it from Call variables.
EnableDescriptionWhether the call-log description can be configured: 0 = off, 1 = on.
DescriptionThe default description. See Call variables for what you can use.
EnablePlayCallRecordingWhether the “play recordings inside the CRM/Helpdesk” option is configurable: 0 = off, 1 = on.
PlayCallRecordingThe default state of recording playback: 0 = off, 1 = on.
EnableForwardCallLogForAnsweredAgentWhether the option below is configurable in the integration.
ForwardCallLogForAnsweredAgentDefault 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.
AttributeDescription
NameIdentifies the request. CallJournal: creates a new call log. CallJournalUpdate: updates an existing log with extra detail.
MethodPOST or PUT.
ResponseTypeJSON (application/json).
RequestEncodingEmpty in this scenario.
URLFormatThe API endpoint URL.
AttributeDescription
NameFixed to Data.
TypeFixed to Body.
ValueThe body parameters, drawn from Cloud Voice’s built-in variables.

Alongside the general Call variables, the call journal can also use:

VariableDescription
{{.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.

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

VariableDescription
Variables from the AuthMethod scenarioCredential values captured during authentication.
Target variables from follow-up requestsValues 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.
{{.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.

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

<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>
AttributeDescription
IdFixed to ChatJournal.
TypeFixed to REST.
SettingDescription
EnableSubjectWhether the synced record’s subject is configurable: 0 = off, 1 = on.
SubjectThe default subject. Defaults to PhoneSystem External Chat Session; you can also build it from the variables below.
EnableCreateTypeReserved; not currently used.
CreateTypeReserved; not currently used.
AttributeDescription
NameIdentifies the request. Fixed to ChatJournalDefault.
MethodPOST or PUT.
ResponseTypeJSON (application/json).
RequestEncodingEmpty in this scenario.
URLFormatThe API endpoint URL.
AttributeDescription
NameFixed to Data.
TypeFixed to Body.
ValueThe body parameters, drawn from Cloud Voice’s built-in variables. Use &#xA; for newlines.

Variables

VariableDescription
Variables from the AuthMethod scenarioCredential values captured during authentication.
Target variables from follow-up requestsValues 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}}.

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

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.

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

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.

<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

Section titled “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).

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

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:

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

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

    <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

Section titled “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.

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

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