View Categories

WhatsApp Flow JSON Structure

3 min read

Every WhatsApp Flow is defined by a JSON document — the Flow JSON — that describes screens, components, and navigation logic. Understanding the structure lets you build any form inside WhatsApp.

Flow JSON is created and managed inside Meta’s Flow Builder (Meta Business Manager → WhatsApp → Flows) or via the Flows API. You do not write it inside Baat — Baat references your Flow by its flow_id.

Top-level structure #

{
  "version": "3.1",
  "screens": [ ... ]
}
  • version — Always "3.1" for current Flows. Use this exact string.
  • screens — An array of screen objects. A Flow must have at least one screen and exactly one terminal screen.

Screen anatomy #

{
  "id": "SCREEN_ID",
  "title": "Screen Title",
  "terminal": false,
  "layout": {
    "type": "SingleColumnLayout",
    "children": [ ...components... ]
  }
}
  • id — Unique identifier for this screen. Referenced in navigation actions.
  • title — Displayed at the top of the screen inside WhatsApp.
  • terminal — Set to true on the final screen (the one with the Submit button). Every Flow must have exactly one terminal screen.
  • layout — Wraps all visual components. Currently only SingleColumnLayout is supported.

Component types #

TextInput #

{
  "type": "TextInput",
  "name": "full_name",
  "label": "Full name",
  "input-type": "text",
  "required": true
}

Collects a single line of text. input-type can be text, number, email, or phone.

TextArea #

{
  "type": "TextArea",
  "name": "issue_description",
  "label": "Describe your issue",
  "required": false,
  "helper-text": "Include your order number if relevant"
}

Multi-line text input. Use for longer free-text responses.

Dropdown #

{
  "type": "Dropdown",
  "name": "service_type",
  "label": "Select a service",
  "required": true,
  "data-source": [
    { "id": "haircut", "title": "Haircut" },
    { "id": "coloring", "title": "Hair Coloring" },
    { "id": "spa", "title": "Spa Treatment" }
  ]
}

RadioButtonsGroup #

{
  "type": "RadioButtonsGroup",
  "name": "contact_preference",
  "label": "How should we contact you?",
  "required": true,
  "data-source": [
    { "id": "whatsapp", "title": "WhatsApp" },
    { "id": "call", "title": "Phone call" }
  ]
}

CheckboxGroup #

{
  "type": "CheckboxGroup",
  "name": "interests",
  "label": "What are you interested in?",
  "required": false,
  "data-source": [
    { "id": "skincare", "title": "Skincare" },
    { "id": "haircare", "title": "Haircare" },
    { "id": "wellness", "title": "Wellness" }
  ]
}

DatePicker #

{
  "type": "DatePicker",
  "name": "appointment_date",
  "label": "Choose a date",
  "required": true,
  "min-date": "2024-01-01",
  "max-date": "2024-12-31"
}

Navigation and actions #

A Footer component (the button at the bottom of each screen) triggers an action when tapped.

Navigate to another screen #

{
  "type": "Footer",
  "label": "Next",
  "on-click-action": {
    "name": "navigate",
    "next": { "type": "screen", "name": "SCREEN_2" },
    "payload": {}
  }
}

Submit the Flow (terminal screen) #

{
  "type": "Footer",
  "label": "Submit",
  "on-click-action": {
    "name": "complete",
    "payload": {}
  }
}

Exchange data with your server (dynamic Flows) #

{
  "type": "Footer",
  "label": "Check availability",
  "on-click-action": {
    "name": "data_exchange",
    "payload": {
      "appointment_date": "${form.appointment_date}"
    }
  }
}

data_exchange sends the current screen’s data to your endpoint synchronously and uses the response to populate the next screen. Use this for dynamic data like real-time slot availability.

Full example — 2-screen lead qualification form #

{
  "version": "3.1",
  "screens": [
    {
      "id": "SCREEN_1",
      "title": "Tell us about you",
      "terminal": false,
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "TextInput",
            "name": "full_name",
            "label": "Your name",
            "input-type": "text",
            "required": true
          },
          {
            "type": "Dropdown",
            "name": "company_size",
            "label": "Company size",
            "required": true,
            "data-source": [
              { "id": "1_10", "title": "1–10 employees" },
              { "id": "11_50", "title": "11–50 employees" },
              { "id": "51_200", "title": "51–200 employees" },
              { "id": "200_plus", "title": "200+ employees" }
            ]
          },
          {
            "type": "Footer",
            "label": "Next",
            "on-click-action": {
              "name": "navigate",
              "next": { "type": "screen", "name": "SCREEN_2" },
              "payload": {}
            }
          }
        ]
      }
    },
    {
      "id": "SCREEN_2",
      "title": "Your requirement",
      "terminal": true,
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "RadioButtonsGroup",
            "name": "monthly_budget",
            "label": "Monthly budget for WhatsApp automation",
            "required": true,
            "data-source": [
              { "id": "under_5k", "title": "Under ₹5,000" },
              { "id": "5k_20k", "title": "₹5,000 – ₹20,000" },
              { "id": "20k_plus", "title": "₹20,000+" }
            ]
          },
          {
            "type": "TextArea",
            "name": "use_case",
            "label": "What do you want to automate?",
            "required": false
          },
          {
            "type": "Footer",
            "label": "Submit",
            "on-click-action": {
              "name": "complete",
              "payload": {}
            }
          }
        ]
      }
    }
  ]
}