Statistics

Queries are made in JSON using an HTTP REST-style request. The query language is based on Druid query language.

Query Types

There are two types of query: Timeseries and Group By.

Query Type: Timeseries

{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-01-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "type",
"value": "reactive"
}
}
cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "type",
"value": "reactive"
}
}' \
"https://api.salemove.com/engagements/stats/count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/engagements/stats/count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'selector',
dimension: 'type',
value: 'reactive'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-01-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "type",
"value": "reactive"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/count",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 5
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 4
},
{
"timestamp": "2017-02-22T00:00:00.000Z",
"count": 2
},
{
"timestamp": "2017-02-23T00:00:00.000Z",
"count": 2
}
]

This type of query takes a timeseries query object and returns an array of JSON objects, where each object represents a value requested by the query.

An example timeseries query object against the /engagements/stats/count endpoint can be found on the right:

A timeseries query includes the following parts:

Property

Required

Description

query_type

Yes

This String should always be timeseries.

granularity

Yes

Defines the granularity to bucket query results. See Granularities.

start_date

Yes

An ISO-8601 timestamp. Defines the query start date (inclusive).

end_date

Yes

An ISO-8601 timestamp. Defines the query end date (exclusive).

filter

Yes

See Filters.

Query Type: Group By

{
"query_type": "group_by",
"dimensions": ["operator_id"],
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "type",
"value": "proactive"
}
}
cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "group_by",
"dimensions": ["operator_id"],
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter":
{
"type": "selector",
"dimension": "type",
"value": "reactive"
}
}' \
"https://api.salemove.com/engagements/stats/count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/engagements/stats/count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'group_by',
dimensions: ['operator_id'],
granularity: 'all',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'selector',
dimension: 'type',
value: 'reactive'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "group_by",
"dimensions": ["operator_id"],
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter":
{
"type": "selector",
"dimension": "type",
"value": "reactive"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/count",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 3,
"operator_id": "f42811bc-8519-4d33-bbb1-36d4555ecb0a"
},
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 2,
"operator_id": "c8b52f0b-ad05-4c71-8c98-5056f07c4d1a"
},
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 2,
"operator_id": "efd1d1d0-dd45-43a3-a028-b4233eaed76b"
}
]

This type of query takes a group by query object and returns an array of JSON objects, where each object represents a grouping asked for by the query. Note: If you only want to do straight aggregates for a given time range, it is highly recommended to use timeseries queries instead. The performance will be substantially better.

An example group_by query object against /engagements/stats/count endpoint can be found on the right:

A group by query includes the following parts:

Parameter

Required

Description

query_type

Yes

This string should always be group_by.

dimensions

Yes

A JSON list of dimensions over which to perform a group-by query.

granularity

Yes

Defines the granularity by which to bucket query results. See Granularities

start_date

Yes

An ISO-8601 timestamp. Defines the query start date (inclusive).

end_date

Yes

An ISO-8601 timestamp. Defines the query end date (exclusive).

filter

Yes

See Filters

Granularities

The granularity field determines how data is aggregated. Supported granularities are all, day, hour, week, and month. all aggregates the data returned into a single bucket. Other granularities may return multiple buckets in a response. Each bucket contains a timestamp field marking the starting point of the bucket. For example, after submitting hour as a granularity:

{
"query_type": "timeseries",
"granularity": "hour",
"start_date": "2017-01-01T05:00:00Z",
"end_date": "2017-01-01T09:00:00Z",
"filter": {}
}

you may get:

[
{
"timestamp": "2017-01-01T05:00:00.000Z",
"count": 20
},
{
"timestamp": "2017-01-01T09:00:00.000Z",
"count": 30
}
]

All empty buckets are discarded. Note that the response may contain only two buckets, although there is a four hour difference between 2017-01-01T05:00:00Z and 2017-01-01T09:00:00Z.

Period Granularities

By default, results are bucketed by their UTC time (e.g., days start at 00:00 UTC). To bucket results in another time zone

{
"type": "period",
"period": $period,
"timeZone": $timezone
}

Where $period is one of:

Value

Description

"PT1H"

Hour.

"P1D"

Day.

"P1W"

Week.

"P1M"

Month.

And $timezone is standard IANA time zone. List of supported time zones

For example, $granularity could be:

{
"type": "period",
"period": "P1D",
"timeZone": "America/Los_Angeles"
}

Filters

A filter is a JSON object indicating which rows of data should be included in the computation for a query. It is essentially the equivalent of the WHERE clause in SQL. You can use the following types of filters.

Selector Filter

"filter":
{
"type": "selector",
"dimension": "$dimension",
"value": "$dimension_value"
}

The simplest filter is a SELECTOR filter. The SELECTOR filter will match a specific dimension with a specific value. SELECTOR filters can be used as the base filters for more complex Boolean expressions of filters.

The grammar for a SELECTOR filter is as shown in the right:

In Filter

"filter":
{
"type": "in",
"dimension": "$dimension",
"values":
[
"$a_dimension_value",
"$a_dimension_value",
"$a_dimension_value"
]
}

IN filter is similar to SELECTOR filter, but instead of matching specific dimension with just one specific value, it matches dimension with multiple possible values.

The grammar for an IN filter is as shown to the right.

Bound filter

Property

Type

Required

Description

type

String

Yes

This should always be "bound".

dimension

String

Yes

The dimension to filter on.

ordering

String

No

Specifies the sorting order to use when comparing values against the bound. Can be one of the following values: "lexicographic", "alphanumeric", "numeric", "strlen"

lower

String

No

The lower bound for the filter.

upper

String

No

The upper bound for the filter.

lowerStrict

Boolean

No

Perform strict comparison on the lower bound ("<" instead of "<=").

upperStrict

Boolean

No

Perform strict comparison on the upper bound (">" instead of ">=").

"filter": {
"type": "bound",
"dimension": <dimension_string>,
"upper": <upper_string>
}

Bound filters can be used to filter on ranges of dimension values. It can be used for comparison filtering like greater than, less than, greater than or equal to, less than or equal to, and "between" (if both "lower" and "upper" are set).

The grammar for a BOUND filter is as shown in the right:

Logical Expression Filters

Logical expression filters AND, OR and NOT can be used to determine whether to include and bucket, include and separate, or exclude data, respectively, based on the selectors you include in your query.

AND

"filter":
{
"type": "and",
"fields":
[
{$a_filter},
{$a_filter},
{$a_filter}
]
}

The grammar for an AND filter is as shown to the right

OR

"filter":
{
"type": "or",
"fields":
[
{$a_filter},
{$a_filter},
{$a_filter}
]
}

The grammar for an OR filter is shown to the right.

NOT

"filter":
{
"type": "not",
"field": {$a_filter}
}

The grammar for a NOT filter is as shown to the right.

The filter specified in a field object can be any other filter defined in this section.

POST Engagement Count

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "group_by",
"dimensions": ["operator_id"],
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "type",
"value": "transfer"
},
{
"type": "selector",
"dimension": "accepted_media",
"value": "video"
}
]
}
}' \
"https://api.salemove.com/engagements/stats/count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/engagements/stats/count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'group_by',
dimensions: ['operator_id'],
granularity: 'all',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'and',
fields: [
{
type: 'selector',
dimension: 'type',
value: 'transfer'
},
{
type: 'selector',
dimension: 'accepted_media',
value: 'video'
}
]
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "group_by",
"dimensions": ["operator_id"],
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "type",
"value": "transfer"
},
{
"type": "selector",
"dimension": "accepted_media",
"value": "video"
}
]
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/count",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 17,
"operator_id": "f42811bc-8519-4d33-bbb1-36d4555ecb0a"
},
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 23,
"operator_id": "c8b52f0b-ad05-4c71-8c98-5056f07c4d1a"
},
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 26,
"operator_id": "efd1d1d0-dd45-43a3-a028-b4233eaed76b"
}
]

Action: POST /engagements/stats/count

Returns engagement count. Possible dimensions that can be used in the filters are:

Dimension

Description

site_id

See engagements for a specific site

operator_id

See engagements for a specific operator

queue_id

See engagements for a specific queue

type

Type of engagements. Possible values are proactive, reactive, transfer

source

reactive engagement starting source (button_embed, callout, hotlink, external_button, tab). See Engagement sources.

outcome

Engagement outcome (accepted, rejected, timed_out, visitor_left, visitor_cancel, operator_cancel, operator_left, error, delivered)

offered_media

See engagements where video, audio, phone, or chat was offered

accepted_media

See engagements where video, audio, phone, or chat was used

POST Engagement Duration

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "highest_visitor_media",
"value": "audio"
}
}' \
"https://api.salemove.com/engagements/stats/duration"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/engagements/stats/duration', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'selector',
dimension: 'highest_visitor_media',
value: 'audio'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "highest_visitor_media",
"value": "audio"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/duration",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 9,
"seconds": 1334,
"average_duration_in_seconds": 152,
"total_duration_in_seconds": 1334
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 3,
"seconds": 568,
"average_duration_in_seconds": 192,
"total_duration_in_seconds": 568
}
]

Action: POST /engagements/stats/duration

Returns the sum and the average of engagement durations in seconds. Possible dimensions that can be used in filters are:

Dimension

Type

Required

Description

site_id

String

Yes

A site_id whose engagements will be included in the calculations

operator_id

String

Yes

An operator_id whose engagements will be included in the calculations

queue_id

String

No

If specified, then the considered engagements will be limited to engagements that resulted from queues of given queue IDs. Transferred engagements are also considered to be resulted from that queue

type

String

No

If specified, then the considered engagements will be limited to engagements by the type. Possible types are proactive, reactive, transfer

highest_operator_media

String

No

If specified, then the considered engagements will be limited to engagements during which the highest media used by the operator was the specified media. Possible media types, from highest to lowest, are video, audio, chat)

highest_visitor_media

String

No

If specified, then the considered engagements will be limited to engagements during which the highest media used by the visitor was the specified media. Possible media types from highest to lowest are video, audio, chat)

end_reason

String

No

If specified, then the considered engagements will be limited to engagements that ended in a certain way. Possible values are transfer and engagement_end

Output

Field

Type

Description

count

Integer

Number of engagements

average_duration_in_seconds

Integer

Average duration of engagements (in seconds)

total_duration_in_seconds

Integer

Total duration of engagements (in seconds)

seconds

Integer

deprecated Use the field total_duration_in_seconds instead

POST Post Engagement Duration

cURL
JavaScript
Ruby
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "highest_visitor_media",
"value": "audio"
}
}' \
"https://api.salemove.com/engagements/stats/post_engagement_duration"
JavaScript
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open(
'POST',
'https://api.salemove.com/engagements/stats/post_engagement_duration',
false
);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'selector',
dimension: 'highest_visitor_media',
value: 'audio'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Ruby
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "highest_visitor_media",
"value": "audio"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/post_engagement_duration",
options
)
response = JSON.parse raw_response.body
puts response

Generates Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 9,
"seconds": 1334,
"average_duration_in_seconds": 152,
"total_duration_in_seconds": 1334
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 3,
"seconds": 568,
"average_duration_in_seconds": 192,
"total_duration_in_seconds": 568
}
]

Action: POST /engagements/stats/post_engagement_duration

Returns the sum and the average of post engagement durations in seconds. Possible dimensions that can be used in filters are:

Dimension

Type

Required

Description

site_id

String

Yes

A site_id whose post engagements will be included in the calculations

operator_id

String

No

An operator_id whose post engagements will be included in the calculations (Only for user_type operator)

queue_id

String

No

If specified, then the considered post engagements will be limited to post engagements that resulted from queues of given queue IDs. Transferred post engagements are also considered to be resulted from that queue

type

String

No

If specified, then the considered post engagements will be limited to engagements by the type. Possible types are proactive, reactive, transfer

highest_operator_media

String

No

If specified, then the considered post engagements will be limited to engagements during which the highest media used by the operator was the specified media. Possible media types, from highest to lowest, are video, audio, chat

highest_visitor_media

String

No

If specified, then the considered post engagements will be limited to engagements during which the highest media used by the visitor was the specified media. Possible media types from highest to lowest are video, audio, chat

user_type

String

No

If specified, then the considered post engagements will be limited to user type. Possible user types are operator, visitor

Output

Field

Type

Description

count

Integer

Number of post engagements

average_duration_in_seconds

Integer

Average duration of post engagements (in seconds)

total_duration_in_seconds

Integer

Total duration of post engagements (in seconds)

seconds

Integer

deprecated Use the field total_duration_in_seconds instead

POST CoBrowsing Count

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "all",
"start_date": "2017-01-29T00:00:00Z",
"end_date": "2017-02-02T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}' \
"https://api.salemove.com/engagements/stats/cobrowsing"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open(
'POST',
'https://api.salemove.com/engagements/stats/cobrowsing',
false
);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-24T00:00:00Z',
filter: {
type: 'selector',
dimension: 'site_id',
value: '2e56b224-6708-4755-b6c9-35f9889e42dd'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "all",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/cobrowsing",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 198
}
]

Action: POST /engagements/stats/cobrowsing

Returns approximate count of engagements where CoBrowsing was used. Possible dimensions that can be used in filters are:

Filters

Type

Required

Description

site_id

String

Yes

A site_id whose engagements will be included in the calculations

operator_id

String

Yes

An operator_id whose engagements will be included in the calculations

POST Visitor Count

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}' \
"https://api.salemove.com/visitors/stats/count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/visitors/stats/count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-22T00:00:00Z',
filter: {
type: 'selector',
dimension: 'site_id',
value: '2e56b224-6708-4755-b6c9-35f9889e42dd'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/visitors"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/count",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 1898
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 2034
}
]

Action: POST /visitors/stats/count

Returns approximate distinct visitor count. This endpoint is using HyperLogLog algorithm to calculate cardinality. Possible dimensions that can be used in filters are:

Dimension

Type

Required

Description

site_id

String

Yes

The site_id of the site whose visitors are included in the calculations

POST Queue Wait Time

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
},
{
"type": "selector",
"dimension": "outcome",
"value": "finished"
}
]
}
}' \
"https://api.salemove.com/engagements/stats/queue/wait_duration"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open(
'POST',
'https://api.salemove.com/engagements/stats/queue/wait_duration',
false
);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-22T00:00:00Z',
filter: {
type: 'and',
fields: [
{
type: 'selector',
dimension: 'site_id',
value: '2e56b224-6708-4755-b6c9-35f9889e42dd'
},
{
type: 'selector',
dimension: 'outcome',
value: 'finished'
}
]
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/engagements"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
},
{
"type": "selector",
"dimension": "outcome",
"value": "finished"
}
]
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/queue/wait_duration",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 7,
"seconds": 0,
"average_duration_in_seconds": 13,
"maximum_duration_in_seconds": 29,
"total_duration_in_seconds": 91,
"short_duration_count": 3,
"within_service_level_count": 10
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 11,
"seconds": 0,
"average_duration_in_seconds": 15,
"maximum_duration_in_seconds": 27,
"total_duration_in_seconds": 165,
"short_duration_count": 5,
"within_service_level_count": 12
}
]

Action: POST /engagements/stats/queue/wait_duration

Returns statistics on how much time visitors have spent waiting in the queue, including average and maximum duration. Possible dimensions that can be used in the filters are:

Dimension

Type

Description

site_id

String

Site ID

team_id

String

Team ID

queue_id

String

Queue ID

media

String

Media type of engagement visitor is queued for (video, audio, chat)

outcome

String

Queuing Outcome. See Outcome descriptions below

from_transfer

Boolean

If engagement was transferred to the queue, then true else false

Outcome

Description

finished

Visitor successfully engaged with operator

canceled

Visitor abandoned the queue

unstaffed

Visitor was forced from the queue, as all operators became unavailable

closed

Visitor was forced from the queue, which was closed by administrative action

disconnected

Visitor disconnected

failed

Visitor failed to join the queue

Output

Field

Type

Description

count

Integer

The number of times visitors enqueued for an engagement

short_duration_count

Integer

The number of times visitors waited less than five seconds

within_service_level_count

Integer

The number of times visitors waited less than the configured Service Level threshold

average_duration_in_seconds

Integer

The average duration that visitors spent waiting in queue (in seconds)

total_duration_in_seconds

Integer

The total duration that visitors spent waiting in queue (in seconds)

maximum_duration_in_seconds

Integer

The maximum duration that visitors spent waiting in queue (in seconds)

seconds

Integer

deprecated Use the field total_duration_in_seconds instead

POST Visit Count

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}' \
"https://api.salemove.com/visits/stats/count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/visits/stats/count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json');
var data = {
query_type: 'timeseries',
granularity: 'day',
start_date: '2017-02-20T00:00:00Z',
end_date: '2017-02-22T00:00:00Z',
filter: {
type: 'selector',
dimension: 'site_id',
value: '2e56b224-6708-4755-b6c9-35f9889e42dd'
}
};
var query = JSON.stringify(data);
xhr.send(query);
var response = JSON.parse(xhr.responseText);
console.log(response);
Untitled
require 'httparty'
ENDPOINT = "https://api.salemove.com/visits"
token = ARGV[0].strip
headers = {
:authorization => "Bearer #{access_token}",
:content_type => "application/json",
:accept => 'application/vnd.salemove.v1+json'
}
options = {
headers: headers,
query: {
"query_type": "timeseries",
"granularity": "day",
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-22T00:00:00Z",
"filter": {
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
}
}
}
raw_response = HTTParty.post(
"#{ENDPOINT}/stats/count",
options
)
response = JSON.parse raw_response.body
puts response

Generates the Output

[
{
"timestamp": "2017-02-20T00:00:00.000Z",
"count": 2023
},
{
"timestamp": "2017-02-21T00:00:00.000Z",
"count": 2094
}
]

Action: POST /visits/stats/count

Returns visitor session count. Possible dimensions that can be used in filters are:

Dimension

Type

Required

Description

site_id

String

Yes

The site_id of the site whose visits are included in the calculations

POST Staffed Visits Count

cURL
Untitled
Untitled
cURL
curl --request POST \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--header "Accept: application/vnd.salemove.v1+json" \
--data-binary '{
"query_type": "timeseries",
"granularity": "all",
"dimensions": ["type"],
"start_date": "2017-02-20T00:00:00Z",
"end_date": "2017-02-24T00:00:00Z",
"filter": {
"type": "and",
"fields":
[
{
"type": "selector",
"dimension": "site_id",
"value": "2e56b224-6708-4755-b6c9-35f9889e42dd"
},
{
"type": "selector",
"dimension": "type",
"value": "staffed"
}
]
}
}' \
"https://api.salemove.com/visits/stats/staffed_count"
Untitled
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.salemove.com/visits/stats/staffed_count', false);
xhr.setRequestHeader('authorization', `Bearer ${accessToken}`);
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('accept', 'application/vnd.salemove.v1+json')