Introduction to Flow JSON

Leverage Flow JSON to build your user experience.

To visualize the complete user experience, use the Builder. The Builder emulates the entire Flow experience and can be updated on the fly. To navigate to the Builder:

  1. Choose your business
  2. Click on All tools in the left side navigation
  3. Open WhatsApp Manager and select your WABA
  4. On the left side navigation, go to Account tools > Flows

See this list of templates you can build with Flow JSON.

Introduction

Flow JSON enables businesses to create workflows in WhatsApp by accessing the features of WhatsApp Flows using a custom JSON object.

These workflows are initiated and run entirely inside WhatsApp. It can include multiple screens, data flows, and response messages.

Flow JSON consists of the following sections:

Flow JSON Section Description

Screen Data Model

Commands to define static types that power the screen.

Screens

Used to compose layouts using standard UI library components.

Components

Individual building blocks that make up a screen (text fields, buttons, and so on).

Routing Model

Defines the rules for the screen by limiting the possible state transition. For example, developers can define that from Screen 1 you can only transition to Screen 2 and 3, but not Screens 4 and 5. These rules are used during server / client side payload validations.

Actions

Special type of syntax to invoke pre-defined logic on the client. All actions are either "navigate" or "complete."

Flow JSON defines the following:

  • Screen
  • Layout
  • Routing Model
  • Components
  • Forms
  • Actions

Top-level Flow JSON Properties

Flow JSON has several required and optional properties that are used in the process of compilation and validation of the Flow.

Required properties

  • version - represents the version of Flow JSON to use during the compilation. Please refer to the list of versions for more details.

  • screens - represents an array or screen as part of the user experience. This is like a set of different pages on your website.

Optional properties

  • data_api_version - represents the version to use during communication with the WhatsApp Flows Data Endpoint. Currently, it is 3.0. If the Flow uses the data-channel capability, the validation system will ask to provide this property.
{
 "version": "2.1",                           
 "screens": [...]

}

Screens

Screens are the main unit of a Flow. Each screen represents a single node in the state machine you define. These properties then make up the Flows screen property model:

"screen" : {
  "id": string,
  "terminal": ?boolean,
  "title": ?string,
  "refresh_on_back": ?boolean,
  "data": ?object,
  "layout": object
}

Required properties

  • id - unique identifier of the screen which works as a page url. SUCCESS is a reserved keyword and should not be used as a screen id.

  • layout - associated screen UI Layout that is shown to the user. Layout can be predefined or it can represent a container with fully customizable content built using WhatsApp Flows Library.

Optional properties

  • terminal (optional) - the business flow is the end state machine. It means that each Flow should have a terminal state where we terminate the experience and have the Flow completed. Multiple screens can be marked as terminal.

  • data (optional) - declaration of dynamic data that fills the components field in the Flow JSON. It uses JSON Schema to define the structure and type of the properties. Below you can find the simple example.

{
  "data": {
    "first_name": {
      "type": "string",
      "__example__": "John"
    }
  }
}
  • title (optional) - screen level attribute that is rendered in the top navigation bar.
  • refresh_on_back (optional) - By default, it is always set to false

Layout

Layout represents screen UI Content. It can be predefined by the WhatsApp Flows team, or the business can use empty containers and build custom experience using the WhatsApp Flows Library.

Layout has the following properties:

  1. type - the layout identifier that’s used in the template. In the current version of Flow JSON, there is only one layout available - "SingleColumnLayout" which represents a vertical flexbox container.

  2. children - represents an array of components from the WhatsApp Flows Library.

Routing Model

Routing model configuration is needed only when you use an Endpoint to power your Flow.

You can define the routing model, which is a directed graph, as each screen can go to multiple other screens. There can be up to a maximum of 10 "branches", or connections, within the routing model.

Consider the following:

The following routing model can be built:

  1. Welcome screen => [Select car model]

  2. Select car mode => [Pick date]

  3. Pick date => [Select car mode, Confirm test drive]

  4. Confirm test drive => []

When to define routes

If you don't use an Endpoint, you don't need to define a routing model, it will be generated automatically. However, if you want to use a server to power your Flow, you'll have to provide a routing_model in your Flow JSON.

How to define routes

Routes are defined per screen via the routing_model property. It is a map of screen ids to an array of other screen ids it can transition to. The terminal screen is defined with terminal=true.

Routing rules

  1. Route cannot be the current screen, but the route can be "refreshed" for validation purposes.

  2. If there is an edge between two screens, then the user can go back and forth between them using the BACK button.

  3. Only forward routes should be specified in the routing model. For example, if you have specified an edge from Screen_A to Screen_B then you shouldn't specify another edge from Screen_B to Screen_A.

  4. Routes can be empty for a screen if there is no forward route from it.

  5. All routes must end at the terminal screen.

Routing Model Flow JSON Example (Endpoint)

In the example below, there is a simple 3-screen Flow that uses an Endpoint. It is expected that the server will return the next screen with a response to data_exchange action. The server has to comply with defined routing_model in the Flow JSON:

{
  "version": "2.1",
  "data_api_version": "3.0",
  "data_channel_uri": "https://whatsapp.com",
  "routing_model": {
    "MY_FIRST_SCREEN": [
      "MY_SECOND_SCREEN"
    ],
    "MY_SECOND_SCREEN": [
      "MY_THIRD_SCREEN"
    ]
  },
  "screens": [
    {
      "id": "MY_FIRST_SCREEN",
      "title": "First Screen",
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Footer",
            "label": "Continue",
            "on-click-action": {
              "name": "data_exchange",
              "payload": {}
            }
          }
        ]
      }
    },
    {
      "id": "MY_SECOND_SCREEN",
      "title": "Second Screen",
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Footer",
            "label": "Continue",
            "on-click-action": {
              "name": "data_exchange",
              "payload": {}
            }
          }
        ]
      }
    },
    {
      "id": "MY_THIRD_SCREEN",
      "title": "Third Screen",
      "terminal": true,
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Footer",
            "label": "Continue",
            "on-click-action": {
              "name": "data_exchange",
              "payload": {}
            }
          }
        ]
      }
    }
  ]
}

Properties

Properties can be static or dynamic. In Flow JSON the property is static if it is not a type binded to a data or form object.

Static properties

Static properties are simple. You set static properties once and they never change. Here is an example (see text and label properties of TextHeading and Footer components). Static properties is the simplest way to start building your Flow. You can always replace them later with dynamic content.

Dynamic properties

Dynamic properties enables you to set the content dynamically based on the server / screen data via the dynamic data reference mechanism, like so: "${data.username}". If you attempt to use the dynamic and static variant of the property together, you will get a compilation error. The dynamic data reference mechanism works with the following data types:

  • string
  • number
  • boolean
  • object
  • array

You can dynamically reference these data types in all the components of Flow JSON. There are two types of dynamic properties:

  • Form properties - "${form.field_name}" (data entered by the user in input fields). This is used to provide access to information that the user entered on the screen.
  • Screen properties - "${data.field_name}" (data provided for the screen). This is used to provide access to information that is passed down by the server or the navigate action from the previous screen.

Declaring screen properties (No endpoint example)

If a screen expects dynamic data, declare it inside the data property. Data declaration uses the standard JSON Schema. A simple Flow example would replace text with dynamic data coming from the message payload:

A few things have been added:

  1. Inside MY_FIRST_SCREEN we declared a data field

  2. Inside the data field we declared hello_world_text. This is the data that we expect to receive for screen.

    • hello_world_text follows the JSON Schema specification to declare the expected type, in this example it is a string.
    • __example__ field serves as mock data for the template, which is useful while you’re developing your template without WhatsApp Flows Data Endpoint integration. This field is mandatory.
  3. In TextHeading we’ve referenced the data via dynamic data reference syntax. ${data} represents an object that came from the WhatsApp Flows Data Endpoint or navigate actions in case of Flow without endpoint. You can treat it as a screen state that was set after the response is received.

  4. Property of the state can be accessed using the following pattern - "${data.property_name}"

Declaring screen properties (Endpoint powered example)

If you want to power the screen by endpoint data, the example above will slightly change.

  1. We've add data_api_version, routing_model and data_channel_uri to indicate that the Flow is connected to server
  2. Flow expects to receive a payload from flow data server containing hello_world_text field.

Forms and Form properties

To get and submit the data entered from users, Flow JSON uses a straightforward concept from HTML - Forms.

HTML Form example:

<form>
  <label for="first_name">First name</label><br>
  <input type="text" id="first_name" name="first_name"><br>
  <label for="last_name">Last name</label><br>
  <input type="text" id="last_name" name="last_name">
  
  <input type="radio" id="html" name="fav_language" value="HTML">
  <label for="html">HTML</label><br>

  <input type="radio" id="css" name="fav_language" value="CSS">
  <label for="css">CSS</label><br>

  <input type="radio" id="javascript" name="fav_language" value="JavaScript">
  <label for="javascript">JavaScript</label>
</form>

This form can also be implemented in Flow JSON as follows:

Using Form properties

Using the example above, we can reference form properties using a "${form.field_name}" binding. This type of binding uses the name property of the interactive inputs to reference its value. You can use form values to submit the data to a Flow data server or pass it to another screen.

Passing data to the next screen:

{
  "type": "Footer",
  "label": "Submit data",
  "on-click-action": {
    "name": "navigate",
    "next": { "type": "screen", "name": "NEXT_SCREEN" },
    "payload": {
      "name": "${form.first_name}",
      "lang": "${form.favourite_language}"
    }
  }
}

Submitting data to the server:

{
  "type": "Footer",
  "label": "Submit data",
  "on-click-action": {
    "name": "data_exchange",
    "payload": {
      "name": "${form.first_name}",
      "lang": "${form.favourite_language}"
    }
  }
}

Building forms guidelines

  • In order to build Forms in Flow JSON you need to use Form components then provide the name and children properties

  • Children properties must be an array of Form components

  • Each Form component has its own property model, however the name property is required in all of them

Interactive components cannot be used outside forms.

Component Can Be Used Outside Forms?

Text (TextHeading, TextSubheading, TextCaption, TextBody)

TextInput

TextArea

CheckboxGroup

RadioButtonsGroup

Footer

OptIn

Dropdown

EmbeddedLink

DatePicker

Form configuration

Initial values of inputs can be initiased using init-values property. error-messages property allows you to set custom error for input. This is useful when you use Flow Data Endpoint to receive user data and you want to indicate that certain fields are incorrect.

Attribute Description
init-values

<key, value> object where

key - Field Name in Component

value - Field Initial Value

type - String, Array< String > or Dynamic init-values="${data.init_values}"

error-messages

<key, value> object where

key - Field Name in Component

value - Error Message

type - String or Dynamic error-messages= "${data.error_messages}"

You set init-values by specifying the field name in the respective component, then mapping it to your desired value.

The data type for init-values must match that of the component as outlined below.

Component init-values data type

CheckboxGroup

Array of Strings

RadioButtonsGroup

String

Text Entry

String

Dropdown

String

For example, if you have the field first_name in one TextInput component, the field second_name in another TextInput component you would set the init-values like so:

Actions

Flow JSON provides a generic way to trigger asynchronous actions handled by a client through interactive UI elements. A limited set of actions are described below:

Flow JSON Reference Description Payload Type

data_exchange

Sending Data to WhatsApp Flows Data Endpoint

Customizable JSON payload on data exchanges { [key:string]: any }

navigate

Triggers the next screen with the payload as its input. The CTA button will be disabled until the payload with data required for the next screen is supplied. When flow_message_version is 3, the Flow initiation happens without a data channel

Static JSON payload

complete

Accepts the termination parameters upon completion of a Flow

Static JSON payload

navigate action

This action is a primary way to navigate between the screens on the Flow. The data that's passed as payload of this action will be available on the next screen through dynamic data referencing - ${data.field_name}

When to use

  1. You need to transition to a new screen without requesting a Flow Data Endpoint.
  2. For static Flows, it's mandatory to transition through this action.
  3. For endpoint powered Flows, it's optional to use this action.

Example

{
  "type": "Footer",
  "label": "Submit data",
  "on-click-action": {
    "name": "navigate",
    "next": { "type": "screen", "name": "NEXT_SCREEN" },
    "payload": {
      "name": "${form.first_name}",
      "lang": "${form.favourite_language}"
    }
  }
}

complete action

Terminates the Flow and sends the response message to the chat thread. The business will receive the termination message bubble on the webhook, together with the flow_token and all of the other parameters from the payload. More information can be found here.

When to use

  1. Your Flow is static and doesn't use Flow Data Endpoint to submit the data.
  2. Use this action on terminal screen as a last interaction of the user. Once triggered, the Flow will be terminated and entered data will be submitted via webhook.

Example

{
  "type": "Footer",
  "label": "Submit data",
  "on-click-action": {
    "name": "complete",
    "payload": {
      "discount_code": "${data.discount_code}",
      "items": "${form.selected_items}"
    }
  }
}

Example of a Flow using navigate and complete actions

data_exchange action

Sends data to WhatsApp Flows Data Endpoint.

When to use

  1. You build a WhatsApp Flows Data Endpoint-powered Flow.
  2. You want to submit the data from screen to your server and transition to the next screen.
  3. You want to update the screen content based on a selected value.

Example

{
  "type": "Footer",
  "label": "Submit data",
  "on-click-action": {
    "name": "data_exchange",
    "payload": {
      "discount_code": "${data.discount_code}",
      "items": "${form.selected_items}"
    }
  }
}

Components

A comprehensive list of components with code examples is available here.

Limitations

Flow JSON content string is limited and cannot exceed 10 MB.