Kindly Docs

Go to App
⌘K
▶️Introduction
🔹Getting started with webhooks
🔹Webhooks reference
🔹Message processing
🔹Pattern dialogues
🔹Context memory
🔹Languages
📄Guides and Examples
◽Checking webhook signatures (HMACs)
◽Example: Chat transcript webhook
◽Kindly Chat authentication
◽Inbox backup to S3 bucket
◽Inbox backup to GCS bucket
◽Add the Spinnaker script tag to your site
◽Set up event tracking with Google Tag Manager (GTM)
⚙️APIs
▪️Application API
▪️Chat API
▪️Chat Transcript API
▪️Handover API
▪️Nudge API
▪️Statistics API
▪️iOS SDK
▪️Android SDK
▪️Text Predict API
▪️Ticket webhooks (BETA)
📦Legacy
📝APIs Changelog
🛡️Security
©️License and Disclaimer
Docs powered by Archbee
APIs

Statistics API

Rationale

We have created a separate service for statistics about your Kindly chatbots. This service is named Sage and lives at sage.kindly.ai. The statistics you can view in the Kindly platform are provided by Sage. You can collect statistics for your own purposes from the same API that the platform uses.

Sage has its own database which contains only non-personal data. When end users chat with chatbots their messages are stored and processed in Kindly's database, and these can be manually or automatically deleted after some time to protect the end user's privacy. The data in Sage's database will not be deleted, but this data doesn't contain the user's message or any personal metadata, only an indication that someone messaged the bot at a specific time. This way we can keep aggregated statistics such as the number of chats per day, while also allowing the end user to have their privacy protected.

Sage auth sequence diagram
Sage auth sequence diagram


If you have the required permissions, you can create a permanent API key in the platform. This long-lived key can be used by a programmatic service you create to obtain short-lived JWTs which can then be used for statistics requests.

Send API key to api.kindly.ai to receive JWT:

Shell
curl --request GET \
  --url 'https://api.kindly.ai/api/v2/bot/<BOT_ID>/sage/auth' \
  --header 'authorization: Bearer <API_KEY>'


Send a request to sage.kindly.ai to test your new token

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/sessions/messages?from=2019-01-01&to=2019-02-01' \
  --header 'authorization: Bearer <JWT>'


About timezones

  • List of tz database time zones

All time values in the database are stored as UTC. If you want results in your local timezone, which takes into consideration daylight saving time and other irregularities, you can provide a tz argument to your API request with the tzdb name of the timezone you want. It would look like this for Oslo:

GET https://sage.kindly.ai/api/...&tz=Europe/Oslo

⚠ Timezone differences

The timezone parameter is important to consider if you are making a request where the data is aggregated by day. If someone messages the bot at 9 p.m. (summertime) on Monday in California, this is stored in the database as occurring at 4 a.m. on Tuesday. To get the API results scoped for California time, you would send a request with tz=America/Los_Angeles. In other words: you must consider the location's timezone and adjust for it.

About granularity

Some aggregations can use a granularity parameter, for example, the aggregation that counts the number of messages per hour, day, or week. You can specify this with granularity=hour, etc. These default to granularity=day if not otherwise specified. Note that hour granularity is only allowed if the time between from and to is one week or less.

About sources and languages

The events that are aggregated by Sage are labeled by which source and language the user and bot were chatting with. Your API requests can be filtered by these values. Not adding any filters to your request will include all data in the results, unfiltered.

Sources

Sources are the different locations where your bot may be deployed. For example:

  • test is source value for conversations by bot builders within the Kindly platform.
  • web is the source value for Kindly Chat deployed on websites, excluding the Kindly platform.
  • app is the source value for chats via the Application API.

If you do not filter by sources, all data will be included in the results, including test data. To select only specific sources, you can send one or more filters like this:

GET https://sage.kindly.ai/api/...&sources[]=web&sources[]=app

You can also select sources to exclude, by prefixing with a minus sign. This means that the API will return data from every source except the ones listed. GET https://sage.kindly.ai/api/...&sources[]=-test

Language codes

The language used for chat between the user and the bot is represented by a two-letter language code. If your bot does not use multiple languages, you can safely ignore this parameter.

If you have multiple languages in your bot and you want to filter by language, you can send one or more filters like this:

GET https://sage.kindly.ai/api/...&language_code[]=en&language_code[]=nb

Statistics APIs

Filtering options

Most of the APIs can be filtered by time, language, and source. To see what your options are for these filters, you can send a request to the /meta/options API.

Example request

Response

JSON
{
  "data": {
    "first": "2019-04-28T07:22:52.825000",
    "last": "2019-09-04T06:48:41.100000",
    "language_codes": ["en", "nb"],
    "sources": ["app", "test", "web"],
    "granularities": ["hour", "day", "week"]
  }
}


Chat sessions

Number of chats where users engaged with the bot

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • granularity (default: day)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/sessions/chats?from=2019-07-01&to=2019-07-07' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "count": 485,
      "date": "2019-07-01T00:00:00.000000"
    },
    {
      "count": 434,
      "date": "2019-07-02T00:00:00.000000"
    },
    {
      "count": 459,
      "date": "2019-07-03T00:00:00.000000"
    },
    {
      "count": 446,
      "date": "2019-07-04T00:00:00.000000"
    },
    {
      "count": 355,
      "date": "2019-07-05T00:00:00.000000"
    },
    {
      "count": 283,
      "date": "2019-07-06T00:00:00.000000"
    }
  ]
}


User messages

Number of messages from users

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • granularity (default: day)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/sessions/messages?from=2019-07-01&to=2019-07-07' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "count": 1661,
      "date": "2019-07-01T00:00:00.000000"
    },
    {
      "count": 1507,
      "date": "2019-07-02T00:00:00.000000"
    },
    {
      "count": 1563,
      "date": "2019-07-03T00:00:00.000000"
    },
    {
      "count": 1572,
      "date": "2019-07-04T00:00:00.000000"
    },
    {
      "count": 1227,
      "date": "2019-07-05T00:00:00.000000"
    },
    {
      "count": 964,
      "date": "2019-07-06T00:00:00.000000"
    }
  ]
}


Fallback rate time series

Number of- and fraction of bot replies that are fallbacks, as an aggregated time series.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • granularity (default: day)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/fallbacks/series?from=2019-07-01&to=2019-07-07' \
  --header 'authorization: Bearer <JWT>'


Response

count represents the number of fallback messages in the given time interval, rate represents which fraction of the total number of bot replies in the time interval are fallbacks.

JSON
{
  "data": [
    {
      "count": 177,
      "date": "2019-07-01T00:00:00.000000",
      "rate": 0.12132805028009291
    },
    {
      "count": 161,
      "date": "2019-07-02T00:00:00.000000",
      "rate": 0.1207012308839985
    },
    {
      "count": 138,
      "date": "2019-07-03T00:00:00.000000",
      "rate": 0.09981955972573078
    },
    {
      "count": 149,
      "date": "2019-07-04T00:00:00.000000",
      "rate": 0.10669992872416251
    },
    {
      "count": 114,
      "date": "2019-07-05T00:00:00.000000",
      "rate": 0.10400945540503682
    },
    {
      "count": 94,
      "date": "2019-07-06T00:00:00.000000",
      "rate": 0.10891544117647059
    }
  ]
}


Fallback rate total

Number of- and fraction of bot replies that are fallbacks, as a total aggregate for the selected time interval.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/fallbacks/total?from=2019-07-01&to=2019-07-07' \
  --header 'authorization: Bearer <JWT>'


Response

count represents the number of fallback messages in the given time interval, rate represents which fraction of the total number of bot replies in the time interval are fallbacks.

JSON
{
  "data": {
    "count": 836,
    "rate": 0.11061601724160727
  }
}


Web client / Kindly Chat pages

Lists most frequent web pages where interactions with the bot have happened. Returns top 3 pages by default, use the limit parameter to request more results.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]
  • limit (default: 3)

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/chatbubble/pages?from=2019-07-01&to=2019-07-07' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "messages": 1615,
      "sessions": 465,
      "web_host": "www.example.com",
      "web_path": "/"
    },
    {
      "messages": 1512,
      "sessions": 428,
      "web_host": "www.example.no",
      "web_path": "/"
    },
    {
      "messages": 784,
      "sessions": 264,
      "web_host": "www.example.com",
      "web_path": "/page"
    }
  ]
}


Number of handovers - time series

The number of handover requests (while open), requests while closed, started handovers, and ended handovers in the requested time period, as a time series.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • granularity (default: day)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/takeovers/series?from=2019-09-16&to=2019-09-23' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "date": "2019-09-16T00:00:00.000000",
      "ended": 40,
      "requests": 58,
      "requests_while_closed": 0,
      "started": 44
    },
    {
      "date": "2019-09-17T00:00:00.000000",
      "ended": 27,
      "requests": 40,
      "requests_while_closed": 0,
      "started": 28
    },
    {
      "date": "2019-09-18T00:00:00.000000",
      "ended": 35,
      "requests": 44,
      "requests_while_closed": 0,
      "started": 35
    },
    {
      "date": "2019-09-19T00:00:00.000000",
      "ended": 55,
      "requests": 88,
      "requests_while_closed": 0,
      "started": 55
    },
    {
      "date": "2019-09-20T00:00:00.000000",
      "ended": 64,
      "requests": 86,
      "requests_while_closed": 0,
      "started": 65
    },
    {
      "date": "2019-09-21T00:00:00.000000",
      "ended": 0,
      "requests": 0,
      "requests_while_closed": 2,
      "started": 0
    },
    {
      "date": "2019-09-22T00:00:00.000000",
      "ended": 0,
      "requests": 0,
      "requests_while_closed": 1,
      "started": 0
    }
  ]
}


Number of handovers - total

The total number of handover requests (while open), requests while closed, started handovers, and ended handovers in the requested time period.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/takeovers/totals?from=2019-09-16&to=2019-09-23' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": {
    "ended": 44,
    "requests": 79,
    "requests_while_closed": 3,
    "started": 47
  }
}


Aggregated chat bubble feedback

If you have enabled the feedback feature in Kindly Chat you can get a summary of the ratings given by users in the period. The API considers the ratings as numbers, with 1 being the lowest rating. Both the count of the number of ratings and the ratio of the total number of ratings is given.

This API only returns aggregated data. If you want to analyze the feedback texts users have given you can get these from an inbox backup. See also: Inbox backup to GCS bucket.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/feedback/summary?from=2019-09-16&to=2019-09-23' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": {
    "binary": [
      {
        "count": 50,
        "rating": 1,
        "ratio": 0.5
      },
      {
        "count": 50,
        "rating": 2,
        "ratio": 0.5
      }
    ],
    "emojis": [
      {
        "count": 0,
        "rating": 1,
        "ratio": 0.0
      },
      {
        "count": 0,
        "rating": 2,
        "ratio": 0.0
      },
      {
        "count": 0,
        "rating": 3,
        "ratio": 0.0
      }
    ]
  }
}


Button clicks

An ordered list of the most clicked buttons in the chatbot, and the dialogues the buttons belong to. Has both a count of the number of occurrences and a ratio of the total amount of button clicks for the period. Returns top 5 results by default. Use the limit parameter to request more data.



Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]
  • limit (default: 5)

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/buttons/most_clicked?from=2019-09-16&to=2019-09-23' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "button_id": "9d09d898-90d5-4ba9-879c-7faa0f3ec629",
      "button_type": "quick_reply",
      "count": 46,
      "dialogue_id": "6a6de8f8-724d-4dc3-adcb-0b30373cfb3b",
      "ratio": 0.12234042553191489
    },
    {
      "button_id": "6b0c5cc7-d612-4f1e-bfd9-6057130146f3",
      "button_type": "dialogue_trigger",
      "count": 26,
      "dialogue_id": "6a6de8f8-724d-4dc3-adcb-0b30373cfb3b",
      "ratio": 0.06914893617021277
    },
    {
      "button_id": "a75a41b7-0132-4c0c-9cf7-82cb500c8af9",
      "button_type": "dialogue_trigger",
      "count": 23,
      "dialogue_id": "6a6de8f8-724d-4dc3-adcb-0b30373cfb3b",
      "ratio": 0.061170212765957445
    },
    {
      "button_id": "17b666ac-0276-478b-a626-8659a90a1a25",
      "button_type": "quick_reply",
      "count": 20,
      "dialogue_id": "c4aaf069-a0b0-4eb1-ba65-81f46f8c8ecc",
      "ratio": 0.05319148936170213
    },
    {
      "button_id": "4f85b25b-b793-4d20-9479-3c2c5b224ebf",
      "button_type": "dialogue_trigger",
      "count": 17,
      "dialogue_id": "72f96a8f-4aaf-4ac2-bb73-1cbec8f2aa57",
      "ratio": 0.04521276595744681
    }
  ]
}


Labels

The most frequent labels added to chats. Returns top 5 labels by default. Use the limit parameter to request more data.

Required parameters

  • from (YYYY-MM-DD)
  • to (YYYY-MM-DD)

Optional parameters

  • tz (default: UTC)
  • sources[]
  • language_codes[]
  • limit (default: 5)

Example request

Shell
curl --request GET \
  --url 'https://sage.kindly.ai/api/v1/stats/bot/<BOT_ID>/chatlabels/added?from=2019-09-16&to=2019-09-23' \
  --header 'authorization: Bearer <JWT>'


Response

JSON
{
  "data": [
    {
      "count": 5,
      "label_id": "35bf04c0-392d-46a0-a741-4d660134d461",
      "label_text": "Some label"
    },
    {
      "count": 2,
      "label_id": "50e57dca-9045-46bf-93d4-55de77795444",
      "label_text": "Another label"
    },
    {
      "count": 2,
      "label_id": "2e08978f-24f0-4207-97c0-8945e19b751e",
      "label_text": "Label 3"
    }
  ]
}


Code example in Python

This example requires Python 3.6 or higher (uses f-strings) and the package requests.

You will need to provide two values yourself, the relevant bot ID and an API key with "read statistics" permissions that you have created at https://app.kindly.ai/bot/BOT_ID/connect/api-keys. The code exchanges the API key for a JWT, uses the JWT to get data about the number of messages per day for the bot's lifetime, then renders the data as a Unicode box-character bar chart.

Python
from time import sleep
from urllib.parse import urljoin

import requests

BOT_ID: int = REPLACE ME
KINDLY_STATISTICS_API_KEY: str = REPLACE ME  # get this from https://app.kindly.ai/workspace/BOT_ID/connect/api-keys
SAGE_API_ROOT = 'https://sage.kindly.ai/api/v1/'

JWT = None


def get_new_jwt():
    url = f'https://api.kindly.ai/api/v2/bot/{BOT_ID}/sage/auth'
    response = requests.get(url, headers={'Authorization': f'Bearer {KINDLY_STATISTICS_API_KEY}'})
    response.raise_for_status()
    return response.json()['jwt']


def sage_request(endpoint, params=None):
    global JWT

    url = urljoin(SAGE_API_ROOT, f"stats/bot/{BOT_ID}/{endpoint.lstrip('/')}")
    while True:
        if JWT is None:
            JWT = get_new_jwt()

        try:
            response = requests.get(url, params, headers={'Authorization': f'Bearer {JWT}'})
            response.raise_for_status()
        except requests.HTTPError as e:
            if e.response.status_code == 401:
                print('401: fetching new JWT before retrying')
                JWT = None
                continue

            if e.response.status_code == 429:
                wait_time = e.response.headers.get('retry-after', 10)
                print(f'429: rate limited: waiting {wait_time}s before retrying')
                sleep(wait_time)
                continue

            raise

        return response.json()['data']


# First, fetch some metadata about the bot
options = sage_request('/meta/options')

first = options['first']
last = options['last']
granularities = options['granularities']
language_codes = options['language_codes']
sources = options['sources']

# Display the metadata
print(
    f"""
The earliest date with data is: {first}
The latest date with data is: {last}
Granularity options are: {granularities}
Language options are: {language_codes}
Source options are: {sources}
"""
)

# Then, fetch data about the number of messages in the time period
messages = sage_request('/sessions/messages', {'from': first, 'to': last})

highest = max(x['count'] for x in messages)
if highest == 0:
    raise Exception('No data found')


# Display the data about the number of messages in the terminal
def bar_chart(label, n, scale=1):
    """
    make a "sideways bar chart" with Unicode box characters
    """
    width = n // scale
    if n == 0:
        bar = ''
    elif width == 0:
        bar = '▍'
    else:
        bar = '█' * width

    return f"{label}: {bar} {n}"


LINE_WIDTH = 80
c = highest // LINE_WIDTH
print(f'Number of messages between {first} and {last}')
print(*(bar_chart(x['date'].split('T', 2)[0], x['count'], scale=c) for x in messages), sep='\n')





Updated 18 Oct 2023
Did this page help you?
PREVIOUS
Nudge API
NEXT
iOS SDK
Docs powered by Archbee
TABLE OF CONTENTS
Rationale
About timezones
⚠ Timezone differences
About granularity
About sources and languages
Sources
Language codes
Statistics APIs
Filtering options
Example request
Response
Chat sessions
Required parameters
Optional parameters
Example request
Response
User messages
Required parameters
Optional parameters
Example request
Response
Fallback rate time series
Required parameters
Optional parameters
Example request
Response
Fallback rate total
Required parameters
Optional parameters
Example request
Response
Web client / Kindly Chat pages
Required parameters
Optional parameters
Example request
Response
Number of handovers - time series
Required parameters
Optional parameters
Example request
Response
Number of handovers - total
Required parameters
Optional parameters
Example request
Response
Aggregated chat bubble feedback
Required parameters
Optional parameters
Example request
Response
Button clicks
Required parameters
Optional parameters
Example request
Response
Labels
Required parameters
Optional parameters
Example request
Response
Code example in Python
Docs powered by Archbee