Web socket API

Note: Check our SDKs

For Node.js and the web we provide a JavaScript SDK, for iOS a Swift SDK. The SDKs are built on top of our Web API that allows you to send and receive messages from Flow.ai in real-time.

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

Request an endpoint

To start a connection you’ll need to make a GET call to the socket.info API method to the API endpoint at https://api.flow.ai. This provides a temporary WebSocket URL.

The socket.info method requires a sessionId and a clientId.

Query parameter Description
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
clientId Check the Channels app of the dashboard to find your unique clientId.

Example calls

CURL

curl -X GET -H "Content-Type: application/json" "https://api.flow.ai/socket.info?clientId=YOUR_CLIENT_ID&sessionId=123432"

JavaScript

var request = require("request");

var options = { method: 'GET', url: 'https://api.flow.ai/socket.info/?clientId=YOUR_CLIENT_ID&sessionId=1234' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

C#

var client = new RestClient("https://api.flow.ai/socket.info?clientId=YOUR_CLIENT_ID&sessionId=1234");
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);

Swift

var request = NSMutableURLRequest(URL: NSURL(string: "https://api.flow.ai/socket.info/?clientId=YOUR_CLIENT_ID&sessionId=1234")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)

Example response

{
  "status": "ok",
  "payload": {
    "endpoint": "wss://api.flow.ai/ws/8c3b7d7ea9400..."
  }
}

Open a connection

The Websocket URL provided by socket.info are single-use and are only valid for 60 seconds, so make sure to connect directly.

Common format

Any message or other kind of event you send or receive has the same JSON format.

{
  "type": "...",
  "payload": {
    ...
  }
}

Fields

Property Description Type
type The message type for example: message.send string
payload The body of the message object

Keep alive

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.

Send the following message:

{
  "type": "ping"
}

We will respond with a pong.

{
  "type": "pong"
}

Sending Messages

The following example shows sending a simple text message

{
  "type": "message.send",
  "payload": {
    "threadId": "58ca9e327348ed3bd1439e7b",
    "traceId": 1519091841664,
    "speech": "Hi there!"
  }
}
Payload fields
Property Description Type
threadId Required. Unique key identifying a user or channel string
traceId Optional number used to track message delivery integer
speech Required. Text of message string

Message Attachment

Instead of text we also support sending attachments. Note: we currently only support sending event sttachments. Image and dile attachments will follow soon.

{
  "type": "message.send",
  "payload": {
    "threadId": "58ca9e327348ed3bd1439e7b",
    "traceId": 1519091841665,
    "speech": "event attachment",
    "attachment": {
      "type": "event",
      "payload": {
        "name": "INTRO"
      }
    }
  }
}
Property Description Type
type Attachment type. Currently this has to be event string
payload Attachment object
Attachment fields
Property Description Type
name Name of the event to trigger string

Originator

Along with every message you can send information about the originator of the message.

{
  "type": "message.send",
  "payload": {
    "threadId": "58ca9e327348ed3bd1439e7b",
    "traceId": 1519091841666,
    "speech": "Turn off the lights in the Living room",
    "originator": {
      "name": "John Doe",
      "role": "external"
    },
  }
}

Profile info

Along with any originator you can send additional profile information

{
  "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://..."
      }
    }
  }
}

Along with every message you can send additional profile info about the sender of the message.

Profile fields
Property Description Type
fullName Complete name string
firstName First name string
lastName Family name string
gender Gender, M, F or U enum
locale Locale code ( ISO ) string
timezone Number of hours of UTC number
country Two letter country code string
email Email address string
picture URL to profile picture string

Metadata

If sending profile data isn’t enough we also support sending a bag of key values

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

Message Metadata

Along with every message you can send additional metadata. Some of this metadata is also used by the AI engine to determine the response.

{
  "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"
        }]
      }
    }
  }
}
Metadata fields
Property Description Type
language Language code ( ISO ) of the message, not the user string
timezone Timezone of the message ( where it was sent ) . Number of hours from UTC number
params Bag of parameters to use within the AI object

Responses

A reply is sent (almost) instantly. The following is replied if the message is successfully delivered.

{
  "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 ..."
}

Receiving Messages

Messages that are replied are in almost the same format as the ones that are send.

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

Advanced Reply Example

Messages can contain a lot of additional data

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

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://api.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>