WhatsApp Flow

Handle & process flow templates

WhatsApp introduced flows, mobile-app-screen like message types.

This type makes collecting user information a breeze and greatly improves your chatbot UX

WCE has out-of-the box support for flows. An example flow template will be as below

"STAGE_NAME":
  type: flow
  message:
    id: flow-id
    name: flow-name
    title: "My Flow Title"
    body: "Flow message body"
    button: flow-btn
  routes:
    "re:.*": "NEXT_STAGE"

WCE tries to keep template signature similar, a flow template can have a title, body and or footer like any other interactive message template.

Draft Flows

During testing, you may have a draft flow. It's easy to include a draft flow in wce templates, simply add a draft attr

"STAGE_NAME":
  type: flow
  message:
    id: flow-id
    draft: true # signal that flow is in draft mode
    name: flow-name
    title: "My Flow Title"
    body: "Flow message body"
    button: flow-btn
  routes:
    "re:.*": "NEXT_STAGE"

Dynamic properties - Passing initial data

You may have a flow that requires initial values (Dynamic Properties). Use cases for this can be if you have a flow that takes in initial dropdown items or just to populate a field with a default value.

The template "template" hook can be used for this, instead of returning a render payload, it also takes in additional_data field that can be used for this.

Same approach also works same for pywce template
"STAGE-NAME":
  type: flow
  # jawce template
  template: "zw.co.dcl.jchatbot.hooks.AuthHook:registerTemplate"
  message:
    id: 1234567890
    draft: true
    name: SCR_REGISTER
    title: "New Account"
    body: "Register with us to access our services"
    button: Register
  routes:
    "re:.*": "STAGE-USER-LOOKUP"

You have to define a template as below

// zw.co.dcl.jchatbot.hooks.AuthHook.java

public class AuthHook extends AbstractHook {
    public AuthHook(HookArgs args) {
        super(args, SessionLocator.getSessionManager());
    }

    /*
      Take current user mobile number and set it as default msisdn
    */
    public Object registerTemplate() {
        // match keys as set in your flow
        Map<String, Object> flowDynamicProps = Map.of(
                "msisdn", this.args.getChannelUser().waId()
        );

        // note that render-payload is set to null
        args.setTemplateDynamicBody(new TemplateDynamicBody(
                WebhookResponseMessageType.INTERACTIVE,
                flowDynamicProps,
                null
        ));

        return args;
    }
}

Flow Response

When user fills your flow form, the engine returns this in the additional data property of the hook model

A (python) hook model is as below.

You will learn more on Hooks in the next section

    @dataclass
    class HookArg:
        user: WaUser
        params: Dict[str, Any] = field(default_factory=dict)
        template_body: TemplateDynamicBody = None
        from_trigger: bool = False
        user_input: str = None
        flow: str = None
        additional_data: Dict[str, Any] = None  # <=== Will contain flow response data
        session_manager: ISessionManager = None

Example on-receive hook to process flow response (assume a template has a hook defined below)

# ecommerce.hooks.auth_service.py

from pywce import HookArg

def login(arg: HookArg) -> HookArg:
  """
  Process flow response data -
  Take user msisdn field and pin field and attempt login
  """
  print(f"Received hook arg: {arg}")

  flow_auth_data = arg.additional_data

  # TODO: attempt auth business logic
  result = LoginService.login(
    username=flow_auth_data.get('msisdn'),
    password=flow_auth_data.get('pin')
  )

  return arg