Turn Context
This context api is currently versioned as 1.0.0-alpha
. This API is still subject to change as the use cases for it crystalise.
The Turn context automatically surfaces information specific to the ongoing conversation from integrated systems via the integrations API. The Turn context is not stored, it is a real time system. As conversations unfold, integrations are polled for supplementary information on the conversation members which may be relevant to support the conversation's goals. This information is displayed in the Turn in realtime.
Turn Integration Library
We've released a Javascript library to help with the development of Turn integrations.
It is available on GitHub at turnhub/turnio-integration or you can install it with
$ npm install @turnio/integration
$ yarn install @turnio/integration
Below is a sample integration that does the following:
- Exposes a table and an ordered list in the context details panel.
- Suggests password reset content in the reply box
- Exposes an menu item that allows one to change a language.
Integrations built with @turnio/integration
can be run as serverless cloud functions on platforms like Google Cloud Functions and similar.
const TurnIntegration = require("@turnio/integration");
const app = new TurnIntegration(process.env.SECRET)
.context("Language", "table", ({ chat, messages }) => ({
Language: "English",
Confidence: "Very high",
}))
.context("A list of things", "ordered-list", ({ chat, messages }) => ["first item", "second item", "third item"])
.suggest(({ chat, messages }) => [
{
type: "TEXT",
title: "Password reset",
body: "To reset your password click the link on the login page.",
confidence: 0.4,
},
])
.action(({ chat, messages }) => [
{
description: "Change Language",
payload: {
really: "yes",
},
options: {
afr_ZA: "Afrikaans",
eng_ZA: "English",
zul_ZA: "Zulu",
},
callback: ({ message, option, payload: { really } }, resp) => {
console.log({ message, option, really });
// Notify the frontend to refresh the context by setting
// the response header
resp.setHeader("X-Turn-Integration-Refresh", "true");
// this is return as JSON in the HTTP response
return { ok: "done" };
},
},
])
.serve();
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Handshake
{
"version": "1.0.0-alpha",
"capabilities": {
"actions": True,
"suggested_responses": True,
"context_objects": [
{
"title": "The title",
"code": "details",
"type": "table"
}
]
}
}
The handshake needs to be performed after the integration is configured. This is a call to the context url with a handshake
query parameter set to true.
Turn context objects can be one of two types, either an ordered-list
or a table
. The type
key is used to identify them.
Every context object has the following keys:
title
, the title of the context block (i.e.Language
orPatient Information
)type
, eitherordered-list
ortable
code
, a unique identifier for this content. This is used to be able to refer to the block when needing to refresh a piece of information in the UI.
Endpoints need to supply a context_objects
key which contains a key for each context object configured by the handshake. The order of the context objects in the context panel is determined by the order they are supplied in the handshake.
A limited subset of Markdown is supported in rendering the values passed as context. The following types are supported:
- *emphasized*
- **strong**
- ~
strike-through~ - [hyperlinks](https://example.org)
Other Markup features like images, headings and lists are not supported.
Retrieving the context, actions and suggestions
When a conversation loads in the user interface, the browser will initiate a request to the integration requesting an update.
The integration will hit your integration url with an HTTP POST
request with the following payload:
{
"chat": {
"owner": "<the phone number>",
"state": "<the state of the chat>",
...
},
"messages": [{
// the 10 most recent inbound and outbound messages
// that are part of this conversation
}]
}
Context Updates
When receiving the HTTP POST
request, you can supply context object updates
under the context_objects
key as per the formats below.
Ordered lists
{
"version": "1.0.0-alpha",
"context_objects": {
"details": ["first time", "*second item*", "~third item~"]
},
"actions": {}
}
Ordered lists have a list as a payload
. They're automatically prefixed with numbers, starting with 1. They do not support any kind of nesting. The key inside context_objects
must match the code in your handshake return.
Tables
{
"version": "1.0.0-alpha",
"context_objects": {
"details": {
"Language": "[Tagalog](https://en.wikipedia.org/wiki/Tagalog_language)",
"Confidence": "Very High"
}
},
"actions": {}
}
Tables have a dictionary as a payload
. The dictionary key is printed in bold text, the dictionary value is printed as normal. The key inside context_objects
must match the code in your handshake return.
Suggested Responses
When receiving the HTTP POST
request, you can supply suggested responses
under the suggested_responses
key as per the format below.
{
"version": "1.0.0-alpha",
"context_objects": {},
"actions": {},
"suggested_responses": [
{
"type": "TEXT",
"title": "Password Reset",
"body": "To reset your password click the link on the login page.",
"confidence": 0.4
}
]
}
Suggested responses can be specified and will be displayed in a select menu above the response textbox. They will be ordered by confidence
Suggested responses have the following keys:
type
, the type of responsetitle
, the title of the responsebody
, the body of the responseconfidence
, confidence score of this response, used for ordering the list
Actions
When receiving the HTTP POST
request, you can supply custom actions
under the actions
key as per the format below.
{
"version": "1.0.0-alpha",
"context_objects": {},
"actions": {
"change_language": {
"description": "Change Language",
"url": "/api/v1/turn/action",
"payload": {
"really": "yes"
},
"options": {
"afr_ZA": "Afrikaans",
"eng_ZA": "English",
"zul_ZA": "Zulu"
}
}
}
}
Actions can be specified and will be displayed in a dropdown above the context. They will POST the payload to the url
specified on the configured integration when clicked.
Actions have the following keys:
description
, the text in the dropdownurl
, path of the integration actionpayload
, payload that will be postedoptions
, (optional) will create a nested menu and add aoption
key to the payload with the selected option.
Example callback JSON payload
{
"address": "+16315551003",
"integration_uuid": "the-uuid-of-the-integration",
"integration_action_uuid": "the-uuid-of-the-action",
"message": {
// the message that was used to trigger this action
},
"option": "afr_ZA",
"payload": {
"really": "yes"
}
}
Refreshing the context and actions
There's a good chance you would want to have the UI refresh the available context and actions after having completed an action.
Immediate refresh
One can force an immediate refresh of the context and actions by returning the X-Turn-Integration-Refresh
header with a value of true
.
There's an example Turn Integration Demo app that shows how to achieve this. The demo application
exposes an opt-in
or opt-out
action depending on the state. Once opted in the context is refreshed to show the new state and the action is refreshed to display only an opt-out
option.
Delayed refresh
Using the integration_uuid
and the integration_action_uuid
one can make an HTTP request to the integration events endpoint. This will trigger Turn to poll your integration and refresh the UI based on the information returned.
Hitting the integration events endpoint
$ curl -X POST "https://whatsapp.turn.io/api/integrations/<your-integration_uuid>/notify/finish" \
-H "Content-Type: application/json" \
-d '{
"integration_action_uuid": "<your-integration-action-uuid>"
}'