Flow JSON Specification & Validation Engine

Flow JSON is the declarative schema developed by Meta to programmatically define screen layouts, interactive components, dynamic data bindings, and screen transition rules for WhatsApp Flows.

SMSPort embeds an automated, real-time validation engine (flow-validator.ts) that enforces Meta Flow v7.3 standards, preventing invalid configurations from breaking at runtime or failing Meta Graph API asset uploads.


1. Top-Level Flow JSON Structure

A valid Flow JSON payload must adhere to the following top-level format:

{
  "version": "7.3",
  "data_api_version": "3.0",
  "routing_model": {
    "SCREEN_A": ["SCREEN_B"],
    "SCREEN_B": []
  },
  "screens": [
    {
      "id": "SCREEN_A",
      "title": "Welcome",
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": []
      }
    },
    {
      "id": "SCREEN_B",
      "title": "Confirmation",
      "terminal": true,
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Footer",
            "label": "Complete Flow",
            "on-click-action": { "name": "complete" }
          }
        ]
      }
    }
  ]
}

Top-Level Property Specifications

Property Type Requirement Description
version string Required The Flow JSON compiler version. Always specify "7.3" for modern flows. Versions < 6.0 are deprecated.
data_api_version string Optional Must be "3.0" when communicating with dynamic Flow endpoints.
routing_model object Required for Endpoints A map defining all permissible forward state transitions between screens.
screens array Required Array containing between 1 and 50 screen definitions.
data_channel_uri string Deprecated Deprecated as of Flow v3.0. Endpoints must be configured via API metadata (endpointUri), not in JSON.

2. Screen Specifications & Constraints

Each object in the screens array represents an independent view within the Flow:

{
  "id": "APPOINTMENT_DETAILS",
  "title": "Select Time",
  "terminal": false,
  "refresh_on_back": false,
  "data": {
    "slots": {
      "type": "array",
      "__example__": [
        { "id": "10am", "title": "10:00 AM" },
        { "id": "2pm", "title": "02:00 PM" }
      ]
    }
  },
  "layout": {
    "type": "SingleColumnLayout",
    "children": []
  }
}

Critical Screen Constraints:

  1. Screen ID Identifier:
    • Must be uppercase alphanumeric with underscores: ^[A-Z0-9_]+$.
    • Must be globally unique across the Flow.
    • Reserved Identifier: SUCCESS is reserved for client-side termination. Using "id": "SUCCESS" is strictly forbidden by Meta.
  2. Mandatory Terminal Screen:
    • Every Flow must define at least one terminal exit point (terminal: true, success: true, or an action with "name": "complete").
    • Footer Requirement: Meta mandates that terminal screens must contain a Footer component to allow users to exit cleanly.
  3. Component Limits:
    • Maximum of 50 components per screen.
    • Layout container type must strictly be "SingleColumnLayout".

3. Routing Model & Directed Graph Integrity

The routing_model acts as a security and integrity whitelist governing screen transitions:

"routing_model": {
  "STEP_1": ["STEP_2"],
  "STEP_2": ["SUMMARY"],
  "SUMMARY": []
}

Routing Rules Enforced by SMSPort:

  • No Self-Referencing: Screens cannot route to themselves (STEP_1: ["STEP_1"] triggers ROUTING_SELF_REFERENCE).
  • Target Verification: Every destination screen listed in an array must exist in screens (ROUTING_DESTINATION_NOT_FOUND).
  • Action Parity: Any navigation button with "action": "navigate" must target a screen declared in the current screen's routing list.
  • Forward-Only: Backwards navigation is handled automatically by the native WhatsApp client header back button; do not add backwards edges to the routing model.

4. Field Uniqueness & Variable Binding

To avoid data collisions when form responses are sent back to your server:

  • Unique Field Names: Every interactive input (TextInput, TextArea, Dropdown, RadioButtonsGroup, CheckboxGroup, ChipsSelector, DatePicker, CalendarPicker, OptIn) must have a unique name attribute within its screen.
  • Dynamic Variable References:
    • ${data.<key>}: Binds to server-provided or mock data declared on the screen.
    • ${form.<field_name>}: References user-entered values from active form fields.
    • SMSPort's validator automatically checks if ${data.xyz} references exist in the screen's data dictionary, alerting you to undefined references before runtime.