NAV Navbar
http Node.js

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:

For server integrations we advice you to take a look at our Messaging API.

Getting started

An overview how the API works:

  1. Request (GET) a WebSocket endpoint
  2. Open a WebSocket connection (WSS)
  3. Send and receive messages
  4. 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:

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:

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.

Send messages using REST API

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.

Receive replies using Webhooks

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

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"
        }
    }]
}]