Introduction
Anyone can integrate with Flow.ai. Whether it's customer facing, like websites and mobile apps, or server-side, like chat and customer service software.
For all these different use-cases we've made dedicated APIs.
Flow Socket API
A real time messaging API that allows you to send and receive messages from Flow using web sockets.
Audience
The Socket API is specifically intended for developers looking to integrate Flow in a client facing app. For example:
- Building a custom web chat widget
- Integrating Flow inside a mobile app
For server integrations we advice you to take a look at our Messaging API.
Getting started
An overview how the API works:
- Request (GET) a WebSocket endpoint
- Open a WebSocket connection (WSS)
- Send and receive messages
- Keep the connection alive
Nonce overview
The nonce (or secret) is created to provide more security for websocket interactions. To enable it, go to your project
and choose the Flow widget integration, select the advanced section, scroll down and check the box ENABLE CLIENT NONCE
How it works:
- If you call us for the first time for a specific
threadId
you don't need to provide anonce
(secret) in response you will receive thenonce
(secret) and you need to store it for this specificthreadId
- A nonce is linked to a
threadId
, that means if you change thethreadId
, you will receive newnonce
in the response - If you have a
nonce
for a specificthreadId
you'll need to provide it in the headersx-flowai-secret
for anyREST
request - If you send a websocket message of the type
message.send
you'll need to send thenonce
in the messagepayload
with a key namednonce
## Requesting an endpoint
Example Request:
curl 'https://sdk.flow.ai/socket.info' \
-H 'x-flowai-secret: SECRET' \
-H 'x-flowai-threadid: THREAD_ID' \
-H 'x-flowai-clientid: CLIENT_ID' \
-H 'x-flowai-sessionid: SESSION_ID' \
-H 'content-type: application/json' \
-H 'accept: */*' \
-H 'sec-fetch-site: same-site' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-dest: empty' \
--compressed
var request = require("request");
var options = {
method: 'GET',
url: 'https://sdk.flow.ai/socket.info',
headers: {
'x-flowai-secret': 'SECRET',
'x-flowai-threadid': 'THREAD_ID',
'x-flowai-clientid': 'CLIENT_ID',
'x-flowai-sessionid': 'SESSION_ID'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
var client = new RestClient("https://sdk.flow.ai/socket.info");
var request = new RestRequest(Method.GET);
request.AddHeader("x-flowai-secret", "SECRET");
request.AddHeader("x-flowai-threadid", "THREAD_ID");
request.AddHeader("x-flowai-clientid", "CLIENT_ID");
request.AddHeader("x-flowai-sessionid", "SESSION_ID");
IRestResponse response = client.Execute(request);
var request = NSMutableURLRequest(URL: NSURL(string: "https://sdk.flow.ai/socket.info/?clientId=YOUR_CLIENT_ID&sessionId=1234")!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.addValue("SECRET", forHTTPHeaderField: "x-flowai-secret")
request.addValue("THREAD_ID", forHTTPHeaderField: "x-flowai-threadid")
request.addValue("CLIENT_ID", forHTTPHeaderField: "x-flowai-clientid")
request.addValue("SESSION_ID", forHTTPHeaderField: "x-flowai-sessionid")
Example response:
200 OK
{
"status": "ok",
"payload": {
"endpoint": "wss://sdk.flow.ai/ws/8c3b7d7ea9400..."
},
"secret": "SECRET"
}
To start a connection you'll need to make a GET
call to the socket.info
API method to the API endpoint at https://sdk.flow.ai
. This provides a temporary WebSocket URL.
The socket.info
method requires a secret
, sessionId
, clientId
, and a threadId
.
Headers | Description |
---|---|
x-flowai-secret | The secret is used for more security |
x-flowai-threadid | The thread ID of the conversation |
x-flowai-sessionid | The sessionId is something unique you need to create for every call. This can be something like a UIUID. Each connection is partly identified on our end using this key |
x-flowai-clientid | Check the Channels app of the dashboard to find your unique clientId. |
Open a connection
The socket URL provided by socket.info
are single-use and are only valid for 60 seconds, so make sure to connect directly.
Common format
{
"type": "...",
"payload": {
...
}
}
Any message or other kind of event you send or receive has the same JSON format.
Attributes
Property | Description |
---|---|
type required | The message type for example: message.send |
payload required | The body of the message |
Keep alive
Example Message:
{
"type": "ping"
}
Example Reply:
{
"type": "pong"
}
When a connection is made we will automatically disconnect if we do not receive any messages within 50 seconds.
In order to keep the connection live we support a ping message.
Sending Messages
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"traceId": 1519091841664,
"speech": "Hi there!"
}
}
The easiest way to send a simple text message in real time
Attributes
Property | Description |
---|---|
threadId required | Unique key identifying a user or channel |
traceId optional | Optional number used to track message delivery |
nonce optional | The secret is used for more security |
speech required | Text of message |
Originator object
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"traceId": 1519091841666,
"nonce": "SECRET",
"speech": "Turn off the lights in the Living room",
"originator": {
"name": "John Doe",
"role": "external"
},
}
}
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"traceId": 1519091841667,
"speech": "has my milk expired?",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://..."
}
}
}
}
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"speech": "I want to book a flight between Amsterdam and Toronto",
"originator": {
"name": "John Doe",
"role": "external",
"metadata": {
"clientNumber": "asddaasq333ee332",
"preference": "A,B,G"
}
}
}
}
With each message you can customize information regarding the sender, user or as Flow calls it, the originator of the message.
Attributes
Property | Description |
---|---|
name string | Name representing the originator |
role string | Either external , or moderator |
profile Profile object | Optional Profile object |
metadata object | Key value pairs with additional info |
Profile object
An originator can contain additional profile information using the profile object
Property | Description |
---|---|
fullName string | Complete name |
firstName string | First name |
lastName string | Family name |
gender string | Gender, M, F or U |
locale string | Locale code (ISO) |
timezone number | Number of hours of UTC |
country string | Two letter country code |
email string | Email address |
picture string | URL to profile picture |
Metadata
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"speech": "I want to book a flight between Amsterdam and Toronto",
"originator": {
"name": "John Doe",
"role": "external"
},
"metadata": {
"language": "en-US",
"timezone": -6,
"params": {
"seats": [{
"value": "Business class"
}]
}
}
}
}
Along with every message you can send additional metadata. Some of this metadata is also used by the AI engine to determine the response.
Attributes
Property | Description |
---|---|
language string | Language code (ISO) of the message, not the user |
timezone number | Timezone of the message (where it was sent). Number of hours from UTC |
params Params object | Bag of parameters to use within the AI |
Params object
Example Params
{
"passengerCount": [{
"value": "2"
}]
}
{
"food": [{
"value": "food-item-22332",
"match": "Pizza Hawaii"
}, {
"value": "food-item-44525",
"match": "Pizza Calzone"
}]
}
The params object resembles the matched result created by the AI engine using entity classification. Each param itself is a list of [{ value }]
objects.
Property | Description |
---|---|
value required | The value of the param |
match optional | Represents a human value |
Attachment
Example Message:
{
"type": "message.send",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"traceId": 1519091841665,
"speech": "event attachment",
"attachment": {
"type": "event",
"payload": {
"name": "INTRO"
}
}
}
}
Instead of simple text messages, Flow also supports sending attachments like files or events.
Attachment attributes
Property | Description |
---|---|
type required | Attachment type. Currently this has to be event |
payload required | Attachment object |
Attachment object
Property | Description | Type |
---|---|---|
name required | Name of the event to trigger |
Responses
Example Reply:
{
"type": "message.delivered",
"payload": {
"traceId": 1,
"threadId": "31ea9df73ca74dfe9329bf68c09b61ce",
"traceId": 1489399519321,
"speech": "hi"
}
}
If there is an error processing a message the server will reply with an error. For example:
{
"type": "error",
"message": "Invalid message format ..."
}
A reply is sent (almost) instantly. The following is replied if the message is successfully delivered.
Receiving Messages
Messages that are replied are in almost the same format as the ones that are sent.
Example or reply
{
"type": "message.received",
"payload": {
"threadId": "57a8a2a8917250d54bcbb596",
"messages": [
{
"fallback": "hallo",
"responses": [
{
"type": "text",
"payload": {
"text": "hallo"
}
}
]
}
],
"originator": {
"userId": "7250d54bcbb59657a8a2a891",
"name": "Gijs van de Nieuwegiessen",
"role": "user",
"profile": {
"fullName": "Gijs van de Nieuwegiessen",
"firstName": "Gijs",
"lastName": "van de Nieuwegiessen",
"locale": "nl",
"gender": "M",
"picture": "https://flowai.s3.eu-central-1.amazonaws.com/identities/profile/5959ca45-318a-4d58-b5e1-b430934b8e23"
}
}
}
}
Example of advanced reply
{
"type": "message.received",
"payload": {
"threadId": "58ca9e327348ed3bd1439e7b",
"messages": [
{
"fallback": "Hi, how can we help?",
"silent": false,
"replyTo": "event attachment",
"originator": {
"userId": "flowai|system",
"name": "system",
"role": "bot",
"profile": {
"picture": "https://flow.ai/img/brains/flowai.svg"
}
},
"actions": [],
"responses": [
{
"type": "text",
"payload": {
"text": "Hi, how can we help?",
"quickReplies": [
{
"label": "Chat with flow.ai",
"value": "Chat with someone from flow.ai",
"type": "text"
},
{
"label": "Call flow.ai",
"value": "What is your phone number?",
"type": "text"
},
{
"label": "Ask a question",
"value": "I want to ask a question",
"type": "text"
}
]
},
"delay": 0
}
],
"flow": {
"flowId": "2afcb930-9335-4e74-abb3-5745d26707f7",
"title": "Intro"
},
"step": {
"stepId": "d3d46698-e526-4252-b70c-e6e5af3338e0",
"title": "INTRO",
"type": "EVENT"
},
"params": {
"event": [
{
"type": "custom",
"value": {
"name": "INTRO"
}
}
]
}
}
],
"originator": {
"userId": "flowai|system",
"name": "system",
"role": "bot",
"profile": {
"picture": "https://flow.ai/img/brains/flowai.svg"
}
}
}
}
Payload fields
Property | Description | Type |
---|---|---|
threadId | Required. Unique key identifying a user or channel | string |
messages | List of Message templates | array |
originator | Similar to the originator when sending messages | object |
Message fields
Property | Description | Type |
---|---|---|
fallback | Speech representation of the message | string |
silent | True if message does not have any output for a user | bool |
replyTo | Optionally contains the text the message is a direct reply to | string |
originator | Originator specific to this message | object |
actions | Optional action names being called | array |
responses | Collection of Response templates | array |
flow | Information about the flow being matched | object |
step | Information about the step being matched | object |
params | Hash table with Parameters | object |
Response fields
We have a complete reference of the JSON responses available
Example
We provide a JavaScript SDK, but the following example demonstrates opening a connection and sending a test message using vanilla JavaScript in the browser.
<html>
<body>
<script>
(function () {
// Vanilla JS example
// When executing this script. Check your development console for any messages
// This identifies the channel we want to connect with
var clientId = 'YOUR CLIENTID'
// Global references to our WebSocket and interval
var ws
var keepalive
// This methos is where we send test messages
function runTestMessages() {
console.info('runTestMessages')
var message = {
"type": "message.send",
"payload": {
"threadId": "jane.doe",
"speech": "event attachment",
"attachment": {
"type": "event",
"payload": {
"name": "MY EVENT"
}
},
"originator": {
"name": "Jane Doe",
"role": "external",
"profile": {
"fullName": "Jane Doe",
"firstName": "Jane",
"lastName": "Doe",
"gender": "F",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://en.wikipedia.org/wiki/File:YellowLabradorLooking_new.jpg"
},
"metadata": {
"clientNumber": "12345",
"preference": "A,B,G"
}
}
}
}
wsSendMessage(message)
}
// Get a new wss endpoint
function getWsEndpoint() {
console.info('Request endpoint')
// socket.info endpoint
var socketInfoUrl = 'https://sdk.flow.ai/socket.info?clientId=' + clientId + '&sessionId=' + Date.now();
// Create a GET request
var req = new XMLHttpRequest();
req.onload = wsEndpointResponse
req.responseType = 'json';
req.open('GET', socketInfoUrl, true);
req.send();
}
// Called when we get a response from socket.info
// validate the response and open a websocket connection
function wsEndpointResponse(e) {
console.info('Received endpoint')
var xhr = e.target;
if(xhr.response.status !== 'ok') {
// This is not OK..
console.error('Error while fetching wss url', xhr.response)
return
}
// Get the endpoint from the response
var endpoint = xhr.response.payload.endpoint
startWebsocket(endpoint)
}
// Open a new websocket connection
function startWebsocket(endpoint) {
console.info('Websocket start connection with endpoint', endpoint)
// Create a new socket
ws = new WebSocket(endpoint);
ws.onopen = wsOnOpen;
ws.onmessage = wsOnMessage;
}
// Handler called when the socket makes a connection
function wsOnOpen(e) {
console.info('Websocket connection open')
// Start the keepalive
wsStartKeepalive()
// Run our test messages
runTestMessages()
}
// Handler called when the socket receives a message
function wsOnMessage(e) {
var json = JSON.parse(e.data)
console.info('Websocket received json', json)
}
// Simple keep alive method (sending pings)
function wsStartKeepalive() {
clearInterval(keepalive)
// Send a ping 30 seconds
keepalive = setInterval(function() {
wsSendMessage({
"type": "ping"
})
}, 30 * 1000)
}
// Helper method for sending messages
function wsSendMessage(message) {
ws.send(JSON.stringify(message))
}
// Start with sending a GET request for a WSS endpoint
getWsEndpoint()
}());
</script>
</body>
</html>
Flow REST API
An API to automate messaging (e.g., chatbots, voice-powered apps and devices)
This API is organized around REST. It has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients.
Our REST API supports cross-origin resource sharing, allowing you to interact securely with our API from a client-side web application (though you should never expose your secret API key in any public client-side code). JSON is returned by all API responses, including errors.
Audience
The API is specifically intended for developers that want to use the Khoros Flow platform within their own technology stack or solution.
Some example use cases are:
- Automating a customer experience solution
- Integrating with a custom backend service
- Other server-side integrations
For use cases that connect with client interfaces, like mobile apps and websites, we offer a real-time websocket API
You call us, we'll call you
The REST API works asynchronous. Unlike other NLP APIs, it will not return a direct reply to a Send message call.
Instead, the API will respond by sending a POST request to your configured webhook url whenever an event takes place.
Synchronous responses
To make life easier, some calls do support an optional synchronous reply mode. If enabled, you'll get a direct reply to your request instead of having to wait for your webhook to be called.
To enable this sync mode add a ?sync=true
query parameter to the URL of the requested API endpoint.
Sending messages
Many types of unstructured content can be sent to the Khoros Flow platform, including text, audio, images, video, and files. Our powerful AI engine will process any query and send back replies using the provided webhook.
Any message that is sent requires a threadId
that relates the message to a specific user, chat or thread. Optionally you can provide a traceId
that will help keep track of the message when you receive delivery events.
Endpoint
All the URLs referenced in the REST API have the following base:
https://api.flow.ai/rest/v1/
Authentication
Authenticate your API requests by providing an API key as a value of Authorization
header. All API requests expect this header to be present.
You can get a new API key within the Organisation settings
section by selecting API Keys
tab and pressing Create a new API Token
button. After that you need to select this API key in Outbound
section of your REST API integration in integrations section and press Save
button.
Text message
Sending a text message
POST rest/v1/messages/:threadId
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"payload": {
"type": "text",
"speech": "Hello",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'text',
speech: 'Hello',
originator: {
name: "John Doe",
role: "external"
}
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Arguments
traceId number | Optional unique number that is passed along to identify the message. Use this to verify message delivery. |
type string | Indicates the type of message. Should be text |
text string | The text or speech message to process. The maximum length of a message is 255 characters. |
metadata object | Optional meta data (see below) |
metadata.language string | Optional language code in ISO format (2 letters) |
metadata.timezone integer | Optional UTF timezone offset in hours |
metadata.params object | Optional parameters |
Originator
Example Message:
{
"payload": {
"type": "text",
"speech": "hello",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
Example Message:
{
"payload": {
"type": "text",
"speech": "hello",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://..."
}
},
"metadata": {
"language": "en",
"timezone": 5,
"params": {
"product": [{
"value": "Dish washer"
}],
"problems": [{
"value": "Noise"
}, {
"value": "Leaks"
}]
}
}
}
}
Example Message:
{
...
"originator": {
"name": "John Doe",
"role": "external",
"metadata": {
"clientNumber": "asddaasq333ee332",
"preference": "A,B,G"
}
}
...
}
With each message you need to provide some information regarding the sender, user or as we call it, the originator of the message.
Each originator has a role
within the conversation. When sending messages to the REST API this can be either external
or moderator
.
The external
role is used to indicate the originator is a customer, end-user or external user sending a message. The moderator
role is reserved for human agents or employees replying to customers or external users.
Specifying the right role is important. When Flow receives a message originating from a moderator
the bot will automatically pause.
Attributes
Property | Description |
---|---|
name string | Name representing the originator |
role string | Either external , or moderator |
profile Profile object | Optional Profile object |
metadata object | Key value pairs with additional info |
Profile object
An originator can contain additional profile information using the profile object
Property | Description |
---|---|
fullName string | Complete name |
firstName string | First name |
lastName string | Family name |
gender string | Gender, M, F or U |
language string | Two letter language code for example fr |
country string | Lowercase, two letter country code |
locale string | Locale code that combines the language and country code for example en-GB |
timezone number | Number of hours of UTC |
email string | Email address |
phoneNumber string | Phone number in E.164 format |
picture string | URL to profile picture |
Event message
POST rest/v1/messages/:threadId
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"payload": {
"type": "event",
"eventName": "MY_EVENT",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'event',
eventName: "MY_EVENT",
originator: {
name: "John Doe",
role: "external"
}
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Trigger events within Flow by sending an event message.
Parameters
threadId string | Unique identifier of the thread |
Arguments
traceId number | Optional unique number that is passed along to identify the message. Use this to verify message delivery. |
type string | Indicates the type of message. Should be event |
eventName string | The name of the event to trigger |
lang string | Optional language code in ISO format (2 letters) |
timezone integer | Optional UTF timezone offset in hours |
params object | Optional parameters |
Location message
POST rest/v1/messages/:threadId
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"payload": {
"type": "location",
"lat": "1232122422",
"long": "2433343343",
"title": "Example title",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'location',
lat: '1232122422',
long: '2433343343',
title: 'Example title',
originator: {
name: 'John Doe',
role: 'external'
}
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Send coordinates
Parameters
threadId string | Unique identifier of the thread |
Arguments
traceId number | Optional unique number that is passed along to identify the message. Use this to verify message delivery. |
type string | Indicates the type of message. Should be location |
lat string | Latitude |
long string | Longitude |
title string | Optional title of location |
lang string | Optional language code in ISO format (2 letters) |
timezone integer | Optional UTF timezone offset in hours |
params object | Optional parameters |
Media message
POST rest/v1/messages/:threadId
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
{
"payload": {
"type": "media",
"mediaType": "image",
"mimetype": "image/png",
"title": "Example title",
"url": "https://source.unsplash.com/random/880x400",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'media',
mediaType: 'image',
mimeType: 'image/png',
title: 'Example title',
url: 'https://source.unsplash.com/random/880x400',
originator: {
name: 'John Doe',
role: 'external'
}
}
}
})
Example Response:
200 OK
{
"status": "ok"
}
The API allows you to send images, files and other media files.
Parameters
threadId string | Unique identifier of the thread |
Arguments
traceId number | Optional unique number that is passed along to identify the message. Use this to verify message delivery. |
type string | Indicates the type of message. Should be media |
mediaType string | Type of media, image , file , audio , or video |
url string | URL of media attachment |
title string | Optional title of location |
mimeType string | Optionally specify the mime-type of the uploaded file, supported media formats are channel specific |
lang string | Optional language code in ISO format (2 letters) |
timezone integer | Optional UTF timezone offset in hours |
params object | Optional parameters |
Sync mode
POST rest/v1/messages/:threadId?sync=true
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true HTTP/1.1
Host: api.flow.ai
{
"payload": {
"type": "media",
"mediaType": "image",
"mimetype": "image/png",
"title": "Example title",
"url": "https://source.unsplash.com/random/880x400",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'media',
mediaType: 'image',
mimeType: 'image/png',
title: 'Example title',
url: 'https://source.unsplash.com/random/880x400',
originator: {
name: 'John Doe',
role: 'external'
}
}
}
})
Example Response:
200 OK
{
"status": "ok",
"activityId": "66832bd8-46b1-42b5-aefb-81856a7680bd",
"agentId": "a_EbAZzSW",
"channelId": "a_EbAZzSW",
"channelName": "gateway",
"threadId": "4a10d62d-79b4-4543-9373-053924209cc7",
"messages": [
{
"fallback": "Hello",
"silent": false,
"replyTo": "hi",
"originator": {
"userId": "flowai|system",
"name": "system",
"role": "bot",
"profile": {
"picture": "https://flow.ai/img/brains/flowai.svg"
}
},
"actions": [],
"responses": [
{
"type": "text",
"payload": {
"text": "Hello"
}
}
],
"intents": [],
"entities": [],
"flow": {
"flowId": "fF5gEqEko",
"title": "Untitled",
"group": "Default",
"metadata": []
},
"step": {
"stepId": "sXaM8etEl",
"title": "Hi",
"type": "INTENT"
},
"slot": false,
"params": {},
"contexts": [],
"meta": {
"msgId": "61cfa141-6b60-47fd-950c-16634d3f2eef",
"prevMsgId": null,
"childMsgId": "4a7c7027-29b7-4768-832d-56a6d1eaa8c6",
"prevChildMsgId": null,
"createdAt": 1632166271745,
"keepTyping": false
}
}
],
"sentiment": 0,
"accuracy": 0,
"originator": {
"userId": "flowai|system",
"name": "system",
"role": "bot",
"profile": {
"picture": "https://flow.ai/img/brains/flowai.svg"
}
},
"traceId": "6beafa70c487a59c:23cab391bd64d5f1:6beafa70c487a59c:1",
"createdAt": "2021-09-20T19:31:12.031Z",
"replyTo": "hi",
"user": {
"name": "M B",
"role": "external",
"profile": {
"fullName": "M B",
"firstName": "M",
"lastName": "B",
"email": "[email protected]",
"locale": "en",
"timezone": 3,
"gender": "U"
}
},
"metadata": {
"params": {}
},
"connectionKey": "a5b2eb9a-cebd-428c-b3e8-8689bd42d842"
}
The Flow REST API is asynchronous. Whenever a request is sent, a result will be returned to the configured webhook endpoint. There are circumstances that won't allow the use of a webhook endpoint to receive results.
For these use cases we provide a synchronous mode for certain endpoints. Instead of returning the result of the API request to your webhook, it's returned directly as a response to the request.
Note: sync mode is an exception and has several limitations for the messaging endpoint. For example, timers and delays cannot work in this mode! If you are considering using the REST API to connect Flow to a client side app, please consider the socket API first.
Query Parameters
sync string | Indicates that this message should be processed in sync mode, the value should be true |
WriteConcern mode
POST rest/v1/messages/:threadId?writeConcern=true
Example Request:
POST rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?writeConcern=true HTTP/1.1
Host: api.flow.ai
{
"payload": {
"type": "media",
"mediaType": "image",
"mimetype": "image/png",
"title": "Example title",
"url": "https://source.unsplash.com/random/880x400",
"originator": {
"name": "John Doe",
"role": "external"
}
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?writeConcern=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
payload: {
type: 'media',
mediaType: 'image',
mimeType: 'image/png',
title: 'Example title',
url: 'https://source.unsplash.com/random/880x400',
originator: {
name: 'John Doe',
role: 'external'
}
}
}
})
Example Response:
200 OK
{
"status": "ok"
}
Because of the asynchronous nature of the REST API, any call made to the endpoint will not guarantee that the system has completed the action when you receive a response.
For example, calling the resolve endpoint will immediately return a response to your request, but actually resolving the conversation might be done at a later time.
Using the writeConcern mode we guarantee the action has completed when you receive the response.
Query Parameters
writeConcern string | Indicates that this message should be processed in writeConcern mode, the value should be true |
Loading messages
Using the REST API you are able to load a list of messages.
Get a list of messages
We provide a way to request the messaging history of a specific threadId
. Each request is limited to 20 entries and supports pagination to retrieve more entries by specifying a page
parameter.
GET rest/v1/messages/:threadId
Example Request
GET rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Query parameters
sync string | Optional parameter for enabling sync mode |
page number | Optional parameter for pagination |
GET rest/v1/messages/:threadId?sync=true&page=3
Example Request
GET rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true&page=3 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/messages/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true&page=3',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok",
"result": {
"history": [
{
"originator": {
"name": "visitor_abc",
"role": "user",
"profile": {}
},
"messages": [
{
"fallback": "test",
"replyTo": null,
"contexts": [],
"params": {},
"intents": [],
"createdAt": "2019-06-25T12:45:11.857Z",
"responses": [
{
"type": "text",
"payload": {
"text": "test"
}
}
]
},
...
]
},
...
],
"threadId": "6ecfd199-853a-448f-9f91-ef397588ff87",
"page": 3,
"pages": 10
}
}
Get a list of threads
This API call provides a way to load a list of threads. A thread represents a conversation and each request is limited to 20 entries. If you need to retrieve more entries we provide pagination using an optional page
parameter.
GET rest/v1/threads
Example Request
GET rest/v1/threads HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/threads',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Query parameters
sync string | Optional parameter for enabling sync mode |
page number | Required parameter for pagination |
GET rest/v1/threads?sync=true
Example Request
GET rest/v1/threads?sync=true&page=1 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/threads?sync=true&page=1',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok",
"result": {
"threads": [
"14ee0879-afa7-45ed-a3db-42c4b538d42c|o_4f4f442c-cd6c-44f1-8f3d-28d9668ab72c",
"2a1b5693-133b-4d92-84e8-005d5350ca2e|o_4f4f442c-cd6c-44f1-8f3d-28d9668ab72c",
"98e1c5a8-1647-42db-bbb5-9d835f53ee95|o_4f4f442c-cd6c-44f1-8f3d-28d9668ab72c",
...
],
"page": "1",
"pages": 100
}
}
Conversation control
Each conversation has a certain state. It can be either open, in handover or resolved. The REST API provides a way to manipulate the state of conversations by sending different actions.
Handover action
Triggering a handover will indicate a conversation needs the attention of a human agent. When triggering the handover the bot is automatically paused for a number of seconds. By default the bot will pause as long as is configured inside the dashboard settings.
Provide secondsToPause
to specify a custom number of seconds to pause.
POST rest/v1/handover/:threadId
Example Request:
POST rest/v1/handover/a4ad8a025763451da6f15f2b50991651|o_21361542-a262-4aaa-8edb-0f8f88e07d89 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
{
"secondsToPause": 600
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/handover/a4ad8a025763451da6f15f2b50991651|o_21361542-a262-4aaa-8edb-0f8f88e07d89',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
{
"secondsToPause": 600
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique threadId |
Arguments
secondsToPause number | Optional. Number of seconds to pause the bot. |
Takeover action (deprecated)
Send a takeover action for a specific thread
Parameters
threadId string | Unique identifier of the thread |
POST rest/v1/takeover/:threadId
Example Request
POST rest/v1/takeover/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/takeover/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Resolve action
Resolving a conversation is similar to archiving or removing a conversation. It's the final state. Once a conversation is resolved it cannot be undone.
POST rest/v1/resolve/:threadId
Example Request:
POST rest/v1/resolve/a4ad8a025763451da6f15f2b50991651|o_21361542-a262-4aaa-8edb-0f8f88e07d89 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/resolve/a4ad8a025763451da6f15f2b50991651|o_21361542-a262-4aaa-8edb-0f8f88e07d89',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Send a resolve action for a specific threadId. Resolve will complete a handover
, resume
the bot and set the control_state
tag with a value of resolved
.
Parameters
threadId string | Unique threadId |
Triggering events
We provide a way to trigger events for specific threads. An example use case can be a customer service agent doing a hand back and triggering a bot flow for a customer.
Get a list of events
This API provides a way to retrieve a list of events that are allowed to be triggered. Be sure that you have events with the ENABLE MANUAL TRIGGER
checkbox checked. You can find this checkbox in the sidebar on the right when you select an event inside the flow designer.
GET rest/v1/trigger/event
Example Request
GET rest/v1/trigger/event HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/trigger/event',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Query parameters
sync string | Optional parameter for enabling sync mode |
GET rest/v1/trigger/event?sync=true
Example Request
GET rest/v1/trigger/event?sync=true HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/trigger/event?sync=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok",
"result": {
"items": [
"EVENT 1",
"EVENT 2",
"EVENT 3"
]
}
}
Trigger an event
Use this API to trigger an event for a specific thread. If you are interested to trigger events for multiple customers at once, please have a look at our instant broadcast API.
POST rest/v1/trigger/event/:threadId
Example Request
POST rest/v1/trigger/event/6ecfd199-853a-448f-9f91-ef397588ff87?eventName=MY_EVENT HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/trigger/event/6ecfd199-853a-448f-9f91-ef397588ff87?eventName=MY_EVENT',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Query parameters
eventName string | Required parameter |
Business hours
Retrieve a list of configured business hours for your project.
GET rest/v1/businesshours
Example Request
GET rest/v1/businesshours HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/businesshours',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok",
}
Query parameters
sync string | Optional parameter for enabling sync mode |
GET rest/v1/businesshours?sync=true
Example Request
GET rest/v1/businesshours?sync=true HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/businesshours?sync=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response:
200 OK
{
"status": "ok",
"businessHours": [
{
"weekdays": [
{
"weekday": "Monday",
"content": [
{
"from": "0:20",
"to": "4:19"
},
{
"from": "10:00",
"to": "22:22"
},
...
]
},
...
],
"holidays": [
{
"holiday": "New Year",
"date": "2019-12-31T00:00:00.000Z"
},
...
],
"label": "test BH",
"timezone": "(UTC+03:00) Minsk"
},
...
]
}
Bot control
We provide the ability to pause and resume bots for specific threads.
Pause
Pause a bot for specific thread
POST rest/v1/pause/:threadId
Example Request
POST rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Resume
Resume a bot for a specific thread
DELETE rest/v1/pause/:threadId
Example Request
DELETE rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{}
import request from "async-request";
const result = await request({
method: 'DELETE',
url: 'https://api.flow.ai/rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Bot status
Retrieve the status of a bot (if it's paused or active) for a specific threadId
GET rest/v1/pause/:threadId
Example Request
GET rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87 HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
threadId string | Unique identifier of the thread |
Query parameters
sync string | Optional parameter for enabling sync mode |
GET rest/v1/pause/:threadId?sync=true
Example Request
GET rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/pause/6ecfd199-853a-448f-9f91-ef397588ff87?sync=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {},
json: true
})
Example Response:
200 OK
{
"status": "ok",
"isPaued": false,
"threadId": "6ecfd199-853a-448f-9f91-ef397588ff87"
}
Broadcast
The broadcast API provides a way to send bulk messages. You can use this API to re-engage or engage with customers without them starting an initial conversation. For example, sending a WhatsApp templated message or SMS (text) message to a phone number (MSISDN) or segment of contacts.
Broadcast to MSISDN
Send a WhatsApp templated message or SMS (text) message to a list of phone numbers (MSISDN).
POST rest/v1/broadcast/instant
Example Request
POST rest/v1/broadcast/instant HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"audience": [{
"name": "John Doe",
"phoneNumber": "+12345678901",
"profile": {}
}],
"channel": {
"channelName": "whatsapp",
"externalId": "+10987654321"
},
"payload": {
"type": "text",
"speech": "I'm searching for the address of your store in New York"
}
}
POST rest/v1/broadcast/instant HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"audience": [{
"name": "John Doe",
"phoneNumber": "+12345678901",
"profile": {}
}],
"channel": {
"channelName": "whatsapp",
"externalId": "+10987654321"
},
"payload": {
"type": "event",
"eventName": "Send template"
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/broadcast/instant',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
audience: [{
name: 'John Doe',
phoneNumber: "+12345678901",
profile: {
}
}],
channel: {
channelName: "whatsapp",
externalId: "+10987654321"
},
payload: {
type: 'event',
eventName: "Send template",
metadata: {
language: "fr",
timezone: "-2",
params: {
customerId: [{
value: "1234223422232"
}]
}
}
}
},
json: true
})
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/broadcast/instant',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
audience: [{
name: 'John Doe',
phoneNumber: "+12345678901",
profile: {
}
}],
channel: {
channelName: "whatsapp",
externalId: "+10987654321"
},
payload: {
type: 'text',
speech: "I'm searching for the address of your store in New York"
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
audience array | A list of originator objects. See audience below |
channel object | See channel below |
payload object | See payload below |
Audience
The intended audience to send a message to. Please see the originator format for more details
name string | Mandatory name, for example Anonymous |
phoneNumber string | Mandatory^1^ MSISDN (phone number in E164 format) |
identifier string | Mandatory^1^ identifier |
profile string | Optional profile data |
1: Either the phoneNumber
or identifier
needs to be provided
Channel
Information about the Flow integration used to send a message from.
channelName string | Type of channel to send the message, see the reference table below |
externalId string | Identifier of the channel to send the message, see the table below where to find this |
channelName
Use the reference table below to determine the channel.channelName
to copy and paste:
Channel | channelName |
---|---|
Google RBM | rbm |
MessageMedia | messagemedia |
Telekom RBM | telekom |
Twilio | twilio |
whatsapp |
|
Khoros | khoros |
Messenger | messenger |
externalId
Within the Khoros Flow dashboard, open the messaging channel you'd like to use to send a message. Use the reference table below to find the value to use within your API call.
Channel | externalId |
---|---|
Google RBM | Project ID |
MessageMedia | Phone Number |
Telekom RBM | Telekom bot ID |
Twilio | Phone Number |
Production phone number | |
Khoros | Phone number |
Messenger | Page ID |
Payload
type string | Should be event or text |
eventName string | Mandatory if type is event . This is the name of the event to trigger |
speech string | Mandatory if type is text . Use this to run text classification. |
metadata object | See metadata below |
Metadata
language object | Optional language to use |
timezone object | Optional UTC timezone offset to use |
params object | Optional params to use |
Broadcast to segments
This broadcast API call provides a way to trigger one or multiple events for specific segments. You can specify either the name of the segment or it's id taken from the Segments list
POST rest/v1/broadcast/instant/segment
Example Request
POST rest/v1/broadcast/instant/segment HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
{
"audience": [{
"name": "MY_SEGMENT_1"
}, {
"id": "ID_OF_MY_SEGMENT_2"
}, {
"name": "MY_SEGMENT_3",
"id": "ID_OF_MY_SEGMENT_3"
}],
"payload": {
"type": "event",
"eventName": "EVENT_NAME"
}
}
import request from "async-request";
const result = await request({
method: 'POST',
url: 'https://api.flow.ai/rest/v1/broadcast/instant/segment',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
body: {
audience: [{
name: 'MY_SEGMENT_1',
}, {
id: 'ID_OF_MY_SEGMENT_2'
}, {
name: 'MY_SEGMENT_3',
id: 'ID_OF_MY_SEGMENT_3'
}],
payload: {
type: 'event',
eventName: 'EVENT_NAME'
}
},
json: true
})
Example Response:
200 OK
{
"status": "ok"
}
Parameters
audience array | A list of segment objects. See audience below |
payload object | A list of event objects. See events below |
Audience
The segment to trigger event for.
name string | Name of your segment, for example MY_SEGMENT_1 |
id string | ID of your segment. Can be obtained here |
1: Either the name
or id
needs to be provided.
Payload
type enum | text/event/location/media |
speech string | used for text message type |
url string | used for media message type |
lat string | tused for location message type |
eventName string | Name of the [event](/docs/triggers/event) to trigger. For example MY_EVENT_1`` |
Get audience segments
This API call provides a way to load a list of segments created in Flow. Segment is a list of your bot's contacts that are grouped by one or multiple conditions.
GET rest/v1/broadcast/segments?sync=true
Example Request
GET rest/v1/broadcast/segments?sync=true HTTP/1.1
Host: api.flow.ai
Content-Type: application/json
Authorization: MY_MESSAGING_API_KEY
import request from "async-request";
const result = await request({
method: 'GET',
url: 'https://api.flow.ai/rest/v1/broadcast/segments?sync=true',
headers: {
'Authorization': 'MY_MESSAGING_API_KEY',
'Content-Type': 'application/json'
},
json: true
})
Example Response
200 OK
{
{
"status": "ok",
"segments": [{
"agentId": "ea6e8bde-8bf3-4bf2-abc1-e4d2865bae10",
"audienceId": "befce22b-7a3e-40fb-8b44-4de3688509f8",
"channels": [
"eazy"
],
"conditions": [],
"contact": "all",
"createdAfterCondition": "2020-07-14T21:00:00.000Z",
"createdAt": "2020-07-15T15:44:05.831Z",
"createdBeforeCondition": "2020-07-15T21:00:00.000Z",
"importCondition": "all_contacts",
"title": "Created on 15th of July (Eazy)",
"type": "segment",
"updatedAt": "2020-07-15T15:44:05.828Z"
},
{
"agentId": "ea6e8bde-8bf3-4bf2-abc1-e4d2865bae10",
"audienceId": "164b9fa3-db65-4aaf-9b07-9eab3b4ff459",
"channels": [
"messenger"
],
"conditions": [{
"condition": "has_tag_name",
"conditionValue": "OPTIN"
}],
"contact": "messenger",
"createdAfterCondition": null,
"createdAt": "2020-07-15T15:44:37.013Z",
"createdBeforeCondition": null,
"importCondition": "all_contacts",
"title": "OPTIN tag (Messenger)",
"type": "segment",
"updatedAt": "2020-07-15T15:44:37.012Z"
}
]
}
Query parameters
sync string | Optional parameter for enabling sync mode |
Webhooks
Webhooks are the way we deliver replies and notify your app of other type of events.
Receiving calls
Creating a webhook endpoint on your server is no different from creating any page on your website.
Webhook data is sent as JSON in the POST
request body. The full event details are included and can be used directly, after parsing the JSON into an Event object.
Your webhook must meet with the following requirements:
- HTTPS support
- A valid SSL certificate
- An open port that accepts
GET
andPOST
requests
Responding to a call
To acknowledge receiving successful webhook call, your endpoint should return a 2xx HTTP status code. All response codes outside this range, including 3xx codes, will indicate to us that you did not receive the webhook call.
This does mean that a URL redirection or a "Not Modified" response will be treated as a failure. we will ignore any other information returned in the request headers or request body.
We will attempt to deliver your webhook calls for up to two 4 hours with an exponential back off. Webhooks cannot be manually retried after this time.
Type of Events
This is a list of all the types of events we currently send. We may add more at any time, so in developing and maintaining your code, you should not assume that only these types exist.
message |
Called whenever Flow is sending reply message for a specific threadId |
history |
Called whenever Flow is sending messaging history for a specific threadId |
threads |
Called whenever Flow is sending list of threads in user's project |
trigger.events |
Called whenever Flow is sending list of events that can be triggered manually |
businessHours |
Called whenever Flow is sending business hours information |
paused |
Called when the AI engine has paused operation for a specific threadId |
resumed |
Called when the AI engine has resumed operation for a specific threadId |
isPaused |
Called whenever Flow is sending bot status for a specific threadId |
inbound |
Called whenever user sends message to Flow from non-rest channel |
outbound |
Called whenever AI engine sends message to user from non-rest channel |
takeover |
Called when the takeover action is executed |
Example
The following example demonstrates opening a connection and sending a test message using vanilla JavaScript in the browser.
<html>
<script>
(function () {
// Vanilla JS example
// When executing this script. Check your development console for any messages
// This identifies specific user's message
var threadId = 'USER_THREAD_ID'
// Can be found within the 'Outbound' section of your REST integration inside the Khoros Flow dashboard
var token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZ2VudElkIjoiODkxZjBiZjQtNmYwYi00NWEyLThiYjUtMDk5MTI3MDdhZjQ0IiwiY2hhbm5lbElkIjoiOWUxYzZhOWUtMjE4ZC00NGFkLTg3OWYtNzEwMjFmMTgyYWU3IiwiaWF0IjoxNTYxMzk1MjM2fQ.sBzBBCplIPMzoOxBkQgkZtm7jN2TIrz_PWcI-bUjiOI'
var url = 'https://api.flow.ai/rest/v1/'
function sendTextMessage() {
console.info('sendTextMessage')
var message = {
"payload": {
"type": "text",
"speech": "test",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://randompicture.org"
}
}
}
}
// Messaging/history endpoint
var messageUrl = url + 'messages/' + threadId
// Create a POST request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('POST', messageUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send(JSON.stringify(message))
}
function sendEventMessage() {
console.info('sendEventMessage')
var event = {
"payload": {
"type": "event",
"eventName": "test_event",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://randompicture.org"
}
}
}
}
// Messaging/history endpoint
var messageUrl = url + 'messages/' + threadId
// Create a POST request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('POST', messageUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send(JSON.stringify(event))
}
function sendLocationMessage() {
console.info('sendLocationMessage')
var location = {
"payload": {
"type": "location",
"lat": "12.3",
"long": "3.21",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://randompicture.org"
}
}
}
}
// Messaging/history endpoint
var messageUrl = url + 'messages/' + threadId
// Create a POST request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('POST', messageUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send(JSON.stringify(location))
}
function sendMediaMessage() {
console.info('sendMediaMessage')
var media = {
"payload": {
"type": "media",
"mediaType": "image",
"url": "https://source.unsplash.com/random/880x400",
"originator": {
"name": "John Doe",
"role": "external",
"profile": {
"fullName": "John Doe",
"firstName": "John",
"lastName": "Doe",
"gender": "M",
"locale": "en-US",
"timezone": -5,
"country": "us",
"email": "[email protected]",
"picture": "https://randompicture.org"
}
}
}
}
// Messaging/history endpoint
var messageUrl = url + 'messages/' + threadId
// Create a POST request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('POST', messageUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send(JSON.stringify(media))
}
function getMessagingHistory() {
console.info('getMessagingHistory')
// Messaging/history endpoint
var historyUrl = url + 'messages/' + threadId
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('GET', historyUrl, true)
req.setRequestHeader('Authorization', token)
req.send()
}
function getMessagingHistorySync() {
console.info('getMessagingHistorySync')
// Messaging/history endpoint
var historyUrl = url + 'messages/' + threadId + '?sync=true'
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponseSync
req.responseType = 'json'
req.open('GET', historyUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function getBusinessHours() {
console.info('getBusinessHours')
// Messaging/history endpoint
var businessHoursUrl = url + 'businesshours'
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('GET', businessHoursUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function getBusinessHoursSync() {
console.info('getBusinessHoursSync')
// Messaging/history endpoint
var businessHoursUrl = url + 'businesshours?sync=true'
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponseSync
req.responseType = 'json'
req.open('GET', businessHoursUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function pauseBotForUser() {
console.info('pauseBotForUser')
// Pause/resume endpoint
var pauseUrl = url + 'pause/' + threadId
// Create a POST request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('POST', pauseUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function resumeBotForUser() {
console.info('pauseBotForUser')
// Pause/resume endpoint
var resumeUrl = url + 'pause/' + threadId
// Create a DELETE request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('DELETE', resumeUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function getBotStatus() {
console.info('getBotStatus')
// Messaging/history endpoint
var businessHoursUrl = url + 'pause/' + threadId
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponse
req.responseType = 'json'
req.open('GET', businessHoursUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function getBotStatusSync() {
console.info('getBotStatusSync')
// Messaging/history endpoint
var businessHoursUrl = url + 'pause/' + threadId + '?sync=true'
//Create a GET request
var req = new XMLHttpRequest()
req.onload = restEndpointResponseSync
req.responseType = 'json'
req.open('GET', businessHoursUrl, true)
req.setRequestHeader('Authorization', token)
req.setRequestHeader("Content-type", "application/json")
req.send()
}
function restEndpointResponse(e) {
console.info('Received response')
var xhr = e.target
if (xhr.status !== 200) {
// This is not OK..
console.error('Error while sending text message', xhr.response)
return
}
// In other case check your webhook url to see the response from Flow
}
function restEndpointResponseSync(e) {
console.info('Received response')
var xhr = e.target
if (xhr.status !== 200) {
// This is not OK..
console.error('Error while sending text message', xhr.response)
return
} else {
console.log(xhr.response)
}
}
// Sending text message
sendTextMessage()
// Sending event message
sendEventMessage()
// Sending location message
sendLocationMessage()
// Sending media message
sendMediaMessage()
// Getting business hours for project
getBusinessHours()
getBusinessHoursSync()
// Getting messaging history
setTimeout(function () {
getMessagingHistory()
getMessagingHistorySync()
}, 1000)
// Pausing bot
setTimeout(function () {
pauseBotForUser()
getBotStatus()
getBotStatusSync()
}, 2000)
// Resuming bot
setTimeout(function () {
resumeBotForUser()
}, 3000)
}())
</script>
</html>
Flow Management API
Authentication
To authorize, use this code:
# With shell, you can just pass the correct header with each request
curl "https://api.flow.ai/v1/projects/:projectId/flows"
-H 'Authorization: Bearer MY_MANAGEMENT_API_KEY'
Make sure to replace
MY_MANAGEMENT_API_KEY
with your API key.
Authenticate your API requests by providing a Management API key as a bearer token. All API requests expect this bearer token to be present.
You can register a new Management API key within your organisation settings.
Flows
Example Flow object:
{
"flowId": "c48b0a06-9727-4735-8886-49286fae78e3",
"projectId": "db3e3895-fe06-4dcc-a7a0-35b0c0ec55c3",
"brainId": "86bc0fa0-25f7-4d3d-9dcf-eaa2a6f810b1",
"title": "Hello World",
"group": "Demo",
"createdAt": "2018-10-24T06:45:19.541Z",
"disabled": false,
"steps": [{
"stepId": "31aef3cf-8c96-442b-9871-7fc9be322da1",
"title": "Hello!",
"type": "INTENT",
"contexts": [],
"intent": {
"intentId": "67841005-31b1-45b3-b939-3879dfd377de",
"title": "Hello_World_Greeting",
"createdAt": "2018-10-24T06:45:19.484Z",
"examples": [{
"entities": [],
"query": "Hello"
}, {
"entities": [],
"query": "Good day"
}, {
"entities": [],
"query": "Good afternoon"
}, {
"entities": [],
"query": "good morning"
}, {
"entities": [],
"query": "hi"
}, {
"entities": [],
"query": "Hey"
}]
},
"actions": [{
"type": "TEXT",
"payload": {
"texts": [
"Hi there! This is a customer service demo bot! ",
"Hello! I am a customer service demo bot!"
],
"quickReplies": [],
"delay": 0
}
}]
}]
}
A Flow represents a conversation topic. It's combines a series of Step objects that the AI engine uses to determine what actions to perform.
The Flow object
Property | Description |
---|---|
flowId string | Unique ID of the Flow |
projectId string | Project ID the Flow belongs to |
brainId string | ID of the AI brain the Flow belongs to |
title string | Name of the Flow |
group string | Group name |
createdAt date string | Date the flow was created |
disabled boolean | Indicates if it should be ignored |
steps array | Collection of Step objects |
The Step object
Example
INTENT
Step:
{
"stepId": "31aef3cf-8c96-442b-9871-7fc9be322da1",
"title": "Hello!",
"type": "INTENT",
"contexts": [],
"actions": [{
"type": "TEXT",
"payload": {
"texts": [
"Simple reply"
],
"quickReplies": [],
"tags": []
}
}],
"intent": {
"intentId": "67841005-31b1-45b3-b939-3879dfd377de",
"title": "Hello_World_Greeting",
"createdAt": "2018-10-24T06:45:19.484Z",
"examples": [{
"entities": [],
"query": "Hello"
}, {
"entities": [],
"query": "hi"
}, {
"entities": [],
"query": "Hey"
}]
}
}
Example
EVENT
Step:
{
"stepId": "c7512efe-9c2e-4cd4-9fdc-11fc1d31dfb8",
"type": "EVENT",
"title": "EVENT NAME",
"contexts": ["31aef3cf-8c96-442b-9871-7fc9be322da1"],
"actions": [{
"type": "TEXT",
"payload": {
"texts": [
"Simple reply"
],
"quickReplies": [],
"tags": []
}
}]
}
Each Step is part of a Flow. Steps are used by the AI engine to determine what reply action to send when for example an intent is matched.
Steps can be related to other steps and configure complex tree like dialog structures,
Property | Description |
---|---|
stepId string | Unique ID of the Step |
title string | Name of the Step |
type string | Type of step. Should be a value of INTENT , EVENT , UNKNOWN , IMAGE , FILE , AUDIO , VIDEO , LOCATION , NOTHING , ANYTHING |
contexts array | Collection of stepIds that precede the step |
intent object | Intent object, required if type is INTENT |
actions array | Collection of Reply actions |
List all Flows
This endpoint retrieves all Flows.
GET /flows/list
var request = require("request");
var options = { method: 'GET',
url: 'https://api.flow.ai/v1/projects/:projectId/flows',
qs: { limit: '5', skip: '0' },
headers:
{
Authorization: 'MY_MANAGEMENT_API_KEY',
} };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
curl "https://api.flow.ai/v1/projects/:projectId/flows"
-H 'Authorization: Bearer MY_MANAGEMENT_API_KEY'
Property | Description |
---|---|
projectId required | Project ID the Flow belongs to |
limit optional | Pagination option. Number of items per response |
skip optional | Pagination option. Number of items to skip |
[{
"flowId": "53ced89e-08e4-40bc-89b8-f7ea02ba6cd5",
"projectId": "db3e3895-fe06-4dcc-a7a0-35b0c0ec55c3",
"brainId": "86bc0fa0-25f7-4d3d-9dcf-eaa2a6f810b1",
"title": "Get started",
"group": "Weather",
"createdAt": "2018-10-24T06:45:03.828Z",
"disabled": false,
"steps": [{
"stepId": "4237653c-ad8d-4bf8-8ff5-da9dd7cb5636",
"type": "INTENT",
"title": "Get started",
"contexts": [],
"actions": ["5bd014ef0838670032b1aa11"],
"intent": "5bd014ef0838670032b1aa16"
}]
}, {
"flowId": "f1a4c7fd-fa2b-4f67-a391-15b9e98d47ea",
"projectId": "db3e3895-fe06-4dcc-a7a0-35b0c0ec55c3",
"brainId": "86bc0fa0-25f7-4d3d-9dcf-eaa2a6f810b1",
"title": "Weather",
"group": "Weather",
"createdAt": "2018-10-24T06:45:03.820Z",
"disabled": false,
"steps": [{
"stepId": "ea8b18e6-eb07-4ad6-8df2-518c43c180e3",
"type": "INTENT",
"title": "What is the weather like",
"contexts": [],
"actions": ["5bd014ef0838670032b1aa13"]
}, {
"stepId": "e010bb48-a51b-48f3-ab46-81ce10f05454",
"type": "SLOT",
"title": "SLOT",
"contexts": ["ea8b18e6-eb07-4ad6-8df2-518c43c180e3"],
"actions": ["5bd014ef0838670032b1aa12"],
"slot": {
"validation": "REQUIRED",
"entityId": "system.query",
"label": "city"
}
}]
}]