🚧

Disclaimer

This is a straight up copy/paste from the article on the internal CM wiki. We are working on a new version of this documentation.

Specification

A CM Bot script consists of three properties on the top level of the
script. These are the 'id' property as well as the 'config' and
'flows' sections.

Below you'll find an example of the main skeleton of a script.

id: "0a532f29-422d-4e55-924a-809fd3a847fb"
config:
  startPriority: 100
  conversationOwners:
    - identifier: 0031612345678
      channel: WhatsApp
  scriptLanguageVersion: 1
  scriptVersion: 1
flows:
  - id: flow1
    description: "Entry flow"
    steps:
      - !entry
        id: entry_step
        matches: ["Hi", "hi"]
        regexMatches: ["^(Hi|hi)$"]
        isCaseSensitive: false
      - !text
        id: first_step
        message: "First message"

Properties

  • id This should be the same guid as the script id in the bot
    configuration database/api.
  • config Configuration section where information is administered
    on which number & channel the script will listen, versioning,
    starting priority and predefined lists.
  • flows Section containing all the flows of the script. At least 1
    flow with an EntryStep is needed to be able to start the script.

Config section

In the config section matters as script metadata, starting priorities
and (links to) dictionaries containing common words can be defined.
Below is a valid example for a complete config section:

config:
  startPriority: 100
  conversationOwners:
    - identifier: 003197008101048
      channel: WhatsApp
  scriptLanguageVersion: 1
  scriptVersion: 1
  defaultDelay: 100
  errorMessage: "Something unexpected occurred during the processing of this conversation."
  sessionTimeout: 1440
  lists:
    positive-answers:
      items:
        - "qui"
        - "top"
    negative-answers:
      source: negative-answers.yml

Properties

  • startPriority Starting of a script is performed on a priority
    basis where a lower number means a higher priority. The first script
    that has a matching startSequence will be started.
  • conversationOwners This is the identifier for the host of the
    conversation with the corresponding channel. This host can be an
    MSISDN in case of SMS or WhatsApp or an arbitrary identifier like
    with Apple Business Chat.
  • scriptLanguageVersion This integer number identifies the version
    of the language that was used to create the script. For now this
    should set to a fixed '1', because no multiple versions exist
    yet.
  • scriptVersion This integer number defines the version of the
    script, where the highest number is the most recent script. It
    should match the version number as registered in the bot
    configuration api.
  • defaultDelay This integer number specifies the number of
    milliseconds to wait between handling steps. If your script runs too
    fast, increase it. A very low number could have the side-effect of
    messages not being in order on the end-user's side.
  • errorMessage This error message will be displayed to the end
    user in case of a fatal error during processing of the script.
  • sessionTimeout Duration in minutes when the chat will be marked
    as timed out. When exceeded the chat will start over when new input
    is received.
  • lists This is a dictionary where named lists can be administered
    either by defining the list itself as seen in the example, or by
    referencing another yaml file with list entries. Working with
    lists is NOT supported yet.

Flows

This section contains the actual script, which is divided into a
collection of flows. Each flow consists of a collection of steps of
different types.

A script will only be able to start if it contains at least one
so-called EntryStep. In this step you'll need to define which words or
sequences will start the script at that specific step. Although not
actively enforced, a flow should have at most one EntryStep. It's
perfectly fine to have a script with multiple flows containing a single
EntryStep. The script will start at the EntryStep that first (in order
of script appearance) matches the start sequence.

Below is an example of a skeleton for a flow with steps.

flows:
  - id: flowX
    description: "Flow x"
    steps:
      - !entry
        id: entry_step
        regexMatches: ["^(Hi|hi)$"]
        isCaseSensitive: false
      - !text
        id: first_step
        message: "First message"

Properties

  • id This is a string identifying the flow.
    • Use unique id's for every flow or the chatbot will fail
    • do NOT use a dot '.' in the id. This isn't actively
      enforced at the moment.
  • description Small note for the script designer. Will not be
    visible to end-users.
  • steps Section containing the steps that build up the script.

Steps

You can use a decent amount of different steps in your flows for
handling different messagetypes, script flow and other logic.

Properties for each type of Step

  • id A value that uniquely recognizes that step within the script.
    • It is currently not actively enforced that the 'id' value must
      be unique.
    • Do NOT use a dot '.' in the id. This isn't actively
      enforced at the moment.
  • delay Integer value that specifies the waiting period in ms
    before processing the next step. Currently this value is ignored and
    the engine defaults to the script setting.
  • actions List of Action items specifying additional tasks to
    perform. Actions will be discussed in the Actions paragraph.

Each of the supported steps will be explained in the following sections.

EntryStep

Object tag: !entry

The EntryStep is used to configure with which starting sequence (start
words) a script will start. The following applies:

  • An EntryStep should be the first step of a Flow.
  • Multiple EntrySteps in a single Flow are not allowed.
  • A script could have multiple EntrySteps as long as each are in a
    different Flow.
  • EntrySteps are matched in script order. The first one that matches
    will be the starting point of the script.

To match a possible starting sequence, one or multiple regular
expressions can be configured which each allow the EntryStep to start
the script (so ANY of the regular expressions could match / concatenated
with OR).

    steps:
      - !entry
        id: entry_step
        regexMatches: ['^(Hi|hi)$']
        isCaseSensitive: false
        allowRestart: false
        doCatchAll: false

Properties

  • regexMatches A string array of possible regular expressions to
    match. Named capture groups are allowed and will be available as
    session variables on a succesful match. (todo: document capture
    groups).
  • isCaseSensitive Will match the regular expression in a case
    sensitive manner if true.
  • allowRestart Allows the script to restart the script in a new
    session in case a previous session was already present. Defaults to
    true.
  • doCatchAll Match on any input and does not restart a running
    session (ignores regexMatches and isCaseSensitive)

A note on using regular expressions Using regular expressions in the
EntryStep opens the possibility to use so-called named capture groups: a
specific pattern within the matched sequence can be extracted or
'captured' and will be stored in a session variable that will have the
same name as the capture group. This will best be explained using an
example:

    steps:
      - !entry
        id: entry_step
        regexMatches: ['^Order (?<orderCode>\d{5})$']
        isCaseSensitive: false

In the above example, all sequences starting with "Order", followed by
a space and exactly 5 digits will be matched. The named capture group is
specified between brackets (?<orderCode>{=html}\d{5}) and the name of
the capture group is "orderCode". As a result, when the end-user
starts the chat with the text "Order 12345", a new session will be
started and a session variable 'orderCode' with value '12345' will
exist within the session.

The old (current) syntax below won't work with regular expressions but
by defining an array of starting words.

    steps:
      - !entry
        id: entry_step
        matches: ["Hi", "hi"]
        isCaseSensitive: false

If you want to add an Catch All (other) flow in a script, add a flow to
the bottom of the flow list. And start with this entry step:

    steps:
      - !<!entry>
        id: help_entry_step
        regexMatches:
          - '\s*\S[\s\S]*'
        isCaseSensitive: false
        allowRestart: false

ApplePayStep

Object tag: !apple_pay

    steps:
      - !apple_pay
        id: ApplePayDemo010
        merchantName: "CM.com for Dutch GP"
        description: "Dutch GP Ticket Reservation"
        orderReference: "b62d1014-1344-45ae-98cb-d876e8a4c1da"
        recipientEmail: "[email protected]"
        currencyCode: "EUR"
        recipientCountryCode: "NL"
        languageCountryCode: "nl"
        billingAddressRequired: false
        shippingContactRequired: false
        lineItems:
          - label: "DEMO EXPERIENCE FEE"
            type: "final"
            amount: 0.1

HandoverStep

Object tag: !handover

This step will actually send a message to the CM Bot Router to perform
some changes to the routing for this account. As a result messages from
and to the CmBot are cut off.

The following applies:

  • Once a handover is performed, the bot itself lost control. In the
    future we will support scenario's where a handover could be given
    back to the bot.
  • The only currently supported scenario is a handover from cm bot to
    Customer Contact.
  • Important For this to work the specific bot-account needs to be
    whitelisted as well as mappings should be configured for the
    channel-specific ChannelAccounts mappings for CustomerContact.
    steps:
      - !handover
        id: handover_step
        removeSources: ["CmBot"]
        removeTargets: ["CmBot"]
        routeTo: CustomerContact

Properties

  • removeSources Array of string values indicating which routing
    rules to remove based on the source component of the rule.
  • removeTargets Array of string values indicating which routing
    rules to remove based on the target component of the rule.
  • routeTo String value indicating the component to forward the
    handover message to.

RoutingMutationStep

Object tag: !routing_mutation

This is a small subset of the actual functionality but it is what's
needed to do handovers (it supercedes the !handover step). Please note
router internal event 'RoutingMutated' is fired on all routing
updates, but only the !disable_component and !enable_component rules
with componentId: CmBot are actually interpreted on the CustomerContact
adapter and signalling the handover call to CustomerContact.

    steps:
      - !routing_mutation
        id: do_handover
        mutations:
          - !disable_component
            componentId: CmBot
        context:
          var1: waarde1
          var2: waarde2
          var3: {someOtherVariable}

context: You can supply dictionary (key/value pairs) that will end
up in the router-session and will travel along with the (router
internal) RoutingMutated event, which will be available in the
ConversationalRouter adapter for CustomerContact / BMProxy. As a result
this context will be available to webcalls to CustomerContact and
BMProxy. It is possible to use variables as values as displayed for
'var3'.

Below is a full example of all supported options of the
RoutingMutationStep:

    steps:
      - !routing_mutation
        id: update_routing_step_all_options
        mutations:
          - !disable_rules
            targetComponentId: CmBot
          - !enable_rules
            targetComponentId: CmBot
          - !remove_rules
            targetComponentId: CmBot
          - !add_rule
            sourceComponentId: BusinessMessaging
            targetComponentId: CmBot
            rulePriority: 1
            ruleId: "new-rule-id"
      - !routing_mutation
        id: update_routing_step_offload_cmbot
        mutations:
          - !disable_component
            componentId: CmBot
          - !enable_component
            componentId: CmBot
          - !remove_component
            componentId: CmBot
        context:
          - var1: waarde1
            var2: waarde2

CC skills/team based routing. Retrieve the ID of the team to which you
want to route the message to. Go to settings -> Teams -> Select a
team, the guid should show at the top. It is also important that under
the CuCo Routing settings, both the Bot router is routed to both Teams.

    steps:
      - !routing_mutation
        id: do_handover
        mutations:
          - !disable_component
            componentId: CmBot
        context:
          ccTeamGUID: {guid}

EndSessionStep

Object tag: !end_session

Will mark the current Chatbot session as Terminated. So-called
catch-all entry-steps that have allowRestart: false will be able to
run again. Optionally one could configure to reset the router-state as
well.

    steps:
      - !end_session
        id: end_session_step
        resetRouter: false

PositionStep

Object tag: !goto

Use the position step to navigate to a different step in the script.

    steps:
      - !goto
        id: gotoStep
        cursor: "flowId.stepId"

Properties

  • cursor The field actually holding the namespaced (concatenated)
    position in the script to go to.

IfStep

Object tag: !if

The IfStep has some very basic support for if..else scenarios and is
most commonly used directly after an InputStep. An IfStep will check the
supplied variable with the supplied value and if they are equal, the
(!position) action will be performed, effectively changing the flow of
the bot script.

Please adhere to these rules when using IfStep:

  • The first IfStep (in script order) that satisfies the condition will
    win and the remaining steps won't be processed.
  • Conditions are matched exactly as specified and are case
    sensitive
    . Specify more IfSteps if you want to match case
    insensitive or be tolerant to slightly off values.
  • If you want to process some list of menu choices, specify a separate
    if for each choice.
  • When you allow for a default or fallthrough scenario, just add a
    step after the last IfStep. If no IfStep has a matching condition,
    that step after the last if will be performed.
  • Important Please be informed that a new step, the LogicStep is
    being developed that allow for a single step to include all this
    logic, as well as support for Regular Expressions.
    steps:
      - !input
        id: ticketQuestionChoice
        var: "ticketQuestionChoice"
      - !if
        id: if_ticketquestion_1
        var: "ticketQuestionChoice"
        value: "Gold Ticket Friday May 1st (€ 99,-)"
        actions:
          - !position
            flowId: question_2Fri
            stepId: question_2Fri
      - !if
        id: if_ticketquestion_2
        var: "ticketQuestionChoice"
        value: "Gold Ticket Sunday May 3rd (€ 396,-)"
        actions:
          - !position
            flowId: question_2Sun
            stepId: question_2Sun
      - !text
        id: ticketQuestionChoice_unknown
        message: "I don't recognise the ticket you chose. Be aware that I'm a chatbot, so please enter the number of your choice (1, 2 or 3)."
        actions:
          - !position
            flowId: if_else_flow
            stepId: if_else_question

Properties

  • var Session variable to match with the value.
  • value Value to match to the supplied session variable.

InputStep

Object tag: !input

Use this step when you want to process a reply supplied by the end-user.
The following rules apply:

  • No support for validation currently exists. Using the new LogicStep
    one could perform some validation using Regular Expressions though.
  • !position actions on !input are not supported
    steps:
      - !text
        id: "ask_for_email_text"
        message: "What is your email address?"
      - !input
        id: emailaddress_input
        var: "emailaddress"
        vars:
          myType: $$type
          myText: $$text

Properties

  • var Session variable name to store the input.
  • vars Mapping from local variables to session variables based on
    the provided input
Input TypeLocal variableDefault valueDescription
Text$$typetextType of the input. Can be used in !logic
$$text""The text content of the message
Media$$typemediaType of the input. Can be used in !logic
$$textMedia.Name='$$mediaName', Uri='$$mediaUri', MimeType='$$mediaMimeType'Textual representation of the provided media input. The local variables are replaced with the given media data
$$mediaName""A caption or title belonging to the media file
$$mediaUri""A unique download URL for the file
$$mediaMimeType""The mime type of the file as indicated by the channel
Location$$typelocationType of the input. Can be used in !logic
$$textLocation.Label='$$locationLabel', Lat=$$locationLatitude, Long=$$locationLongitudeTextual representation of the provided location input. The local variables are replaced with the given data
$$locationLatitude""Latitude of the location (can be negative) and is always formated with a "." notation (4.1234)
$$locationLongitude""Longitude of the location (can be negative) and is always formated with a "." notation (4.1234)
$$locationLabelName of the location
$$locationSearchQuery""Address or search query of the location

InputStep Media

    steps:
      - !input
        id: text
        var: media
        vars:
          myType: $$type
          myMimeType: $$mediaMimeType
          myName: $$mediaName
          myUri: $$mediaUri
      - !text
        id: outputMedia
        message: "{myType}: {myMimeType} {myName} {myUri}"
      - !text
        id: outputMediaAsText
        message: media

InputStep Location

    steps:
      - !input
        id: text
        var: location
        vars:
          myType: $$type
          myLatitude: $$locationLatitude
          myLongitude: $$locationLongitude
          mySearchQuery: $$locationSearchQuery
          myLabel: $$locationLabel
      - !text
        id: outputLocation
        message: "{myType} {myLatitude} {myLongitude} {mySearchQuery} {myLabel}"
      - !text
        id: outputLocationAsText
        message: location

VarStep

Object tag: !var

This step sets variables the bot can use to make decisions or provide
information to another system.

    steps:
      - !var
        id: set_var
        set:
          foo: "bar"
          customVar: "example.{$chatId}"

Properties

  • set Dictionary where the keys become available as variables in
    the bot script with the assigned value. It is possible to
    concatenate multiple existing variables into a new one like the
    customVar example.

ListPickerStep

Object tag: !listpicker Channels: Apple Business Chat and
WhatsApp

This type of message offers a simpler and more consistent way for users
to make a selection when interacting with a business.

[Apple_listpicker_example.png]{.image} [Listpicker-whatsapp.png]{.image}

    steps:
      - !<!listpicker> 
        id: Listpicker-1
        header: Welcome to Jaspers!
        buttonTitle: Options
        buttons:
          - id: '11-13 Battersea Rise, SW11 1HG'
            title: Jaspers Clapham
          - id: '419 Coldharbour Ln, SW9 8LH'
            title: Jaspers Brixton
          - id: '15 Goldhawk Rd, W12 8QQ'
            title: Jaspers Shepherd's Bush
        body: Let us know how we can help you today by choosing your local store.
        footer: ''
        mediaUri: ''

Properties

  • header The header of the listpicker.
  • buttonTitle Title shown on the button to open the listpicker
    itself.
  • buttons.id The description to show for the option.
  • options.title The title of the option.
  • body Subheader on apple business chat body text on WhatsApp
  • footer An optional footer text that will be rendered in a
    smaller font.
  • mediaUri The location of the image to show.

ReplyButtonsStep

Object tag: !replybuttons Channels: WhatsApp

You can specify a ReplyButtonsStep if you want to render a pre-defined
list of options inside WhatsApp like the example below:

[Reply-buttons-whatsapp.png]{.image}

    steps:
      - !<!replybuttons> 
        id: ReplyButtons-1
        header: ''
        buttons:
          - id: 'yes'
            title: 'Yes'
          - id: 'no'
            title: 'No'
          - id: visit-website
            title: Visit Website
        body: >-
          Here's our 'Running Half-Zip Long-Sleeved Shirt'. Would you like to
          order?
        footer: We only have a medium left in stock

Properties

  • header The header of the message (optional).
  • buttons.id Text to identify the selected button with.
  • buttons.title The title of the button.
  • body Body of the message above the reply buttons
  • footer An optional footer text that will be rendered in a
    smaller font.

LocationStep

Object tag: !location

You can use a location step to communicate an exact location that will
render as a 'pin'.

    steps:
      - !location
        id: "location_step"
        latitude: 51.588928
        longitude: 4.780410
        label: "The Tosti Club Breda"
        searchQuery: "Vlaszak 2, 4811 GR Breda"

Properties

  • latitude Latitude of the location. Please make sure to use a dot
    for the decimal part.
  • longitude Longitude of the location. Please make sure to use a
    dot for the decimal part.
  • label The label to display next to the pin.
  • searchQuery The address to display.

LogicStep

Object tag: !logic

    steps:
      - !logic
        id: logic_id
        entries:
          - condition: !equals
              var: "var1"
              tests: ["1", "One"]
              isCaseSensitive: true
            position:
              cursor: choice_1.choice_1
          - condition: !startsWith
              var: "var1.1"
              tests: ["A", "B"]
              isCaseSensitive: true
            position:
              cursor: "flow11.step11"
          - condition: !and
              conditions:
                - !equals
                  var: "var2"
                  tests: ["2", "Two"]
                  isCaseSensitive: true
                - !equals
                  var: "var2"
                  tests: ["Deux", "Zwei"]
                  isCaseSensitive: true
            position:
              cursor: choice_2.choice_2
          - condition: !or
              conditions:
                - !equals
                  var: "var3"
                  tests: ["3", "Three"]
                  isCaseSensitive: true
                - !equals
                  var: "var3"
                  tests: ["Trois", "Drei"]
                  isCaseSensitive: true
            position:
              cursor: choice_3.choice3
          - condition: !not
              condition: !equals
                var: "var4"
                tests: ["4", "Four"]
                isCaseSensitive: true
            position:
              cursor: choice_4.choice4
          - condition: !regex
              var: "var5"
              tests: ['Order (?<orderCode>)\d{5} for (?<personCount>\d{1}) persons.', "Order (?<orderCode>)\\d{5} for (?<personCount>\\d{1}) persons."]
              isCaseSensitive: true
            position:
              cursor: choice5.choice5
          - condition: !emailValidator
              var: "var6"
            position:
              cursor: "correct.email"
          - condition: !default {}
            position:
              cursor: "if_all_else_fails"

MediaStep

Object tag: !media

Use a mediastep to send a message containing a picture, movie or sound.

    steps:
      - !media
        id: "media_step"
        mediaName: "Race Engineer"
        mediaUri: "https://cdn.cm.com/dgp/DGP-race-engineer.mp3"
        mimeType: "audio/mpeg3"

Properties

  • mediaName The name that will be displayed.
  • mediaUri The location where the media file can be found.
  • mimeType The mimetype of the media. Common types are:
    • image/jpeg
    • image/png
    • image/gif (animated gifs are not supported at
      BusinessMessaging/WhatsApp at the moment)
    • audio/mpeg3
    • video/mpeg4

StepGroupStep

Object tag: !stepgroup Supported Channels: Apple Business Chat

Normally, every step that results in a message being sent, will be
communicated as a single message to Business Messaging. When some
messages are sent with little time in between, the messages might end up
in a different order at the end-user. Since BusinessMessaging supports
sending multiple messages in a single request, the StepGroupStep was
built.

Please note We've only had success with this solution on the Apple
Business Chat channel. It does work in WhatsApp as well, but we've
noticed messages in wrong order as well. The example is taken from a
live script that works on Apple Business Chat.

    steps:
      - !stepgroup
        id: stepgroup_step
        steps:
          - !text_with_url
            id: subflow_event_tvgo_url_link
            textMessage: "Remek választás! Bővebb információért koppints ide:"
            url: "https://www.tvgo.hu/cikk/25890886_universal_filmek_felaron_a_tv_go_n_advent_3"
            urlLabel: "TVGO"
            mediaName: "figure%20skating.png"
            mediaUri: "https://d15k2d11r6t6rl.cloudfront.net/public/users/Integrators/371a907d-72a2-4e4e-8549-723bc6aba3dc/d7df6908-f9ac-41ac-91a5-f1e74e5a4085/1_TVGO_Link.JPG"
            mediaMimeType: "image/png"
          - !text
            id: subflow_event_tvgo_url_msg
            message: "Ha újra szeretnéd indítani a beszélgetést, akkor írd be, hogy „szia”"

Properties

  • steps Array containing Steps to be sent in one go. Imporant
    Only Steps that actually send a message will work here. This is
    not actively validated.

TextStep

Object tag: !text

The TextStep is used to send a plain text message to the recipient. The
following applies.

  • It is allowed to use unicode emoticons, like the text 'Hey
    there👋!'
  • Use \n as a newline separator within a single yaml line.
  • Use |- to start a block so newlines in yaml will be preserved.
    This make the yaml more readable when using big text blocks.
  • You can have as many TextSteps as you want.

To match a possible starting sequence, one or multiple regular
expressions can be configured which each allow the EntryStep to start
the script (so ANY of the regular expressions could match / concatenated
with OR).

    steps:
      - !text
        id: text_1
        message: "This message will be sent to the recipient."
      - !text
        id: text_2
        message: "It is allowed to interpolate variables here, like {$channel}"     todo: document variable types.
      - !text
        id: text_3
        message: "First line \n Second line"
      - !text
        id: stext_4
        message: |-
          This will be the first line.
          This will be the second line.

Properties

  • message Content of the text-message that will be sent.

TextWithUrlStep

Object tag: !text_with_url Supported Channels: Apple Business
Chat

This message feels somewhat hacky and was built to solve an Apple
Business Chat problem, where we had to send a text message, that comes
with a so-called 'rich link'. The rich link translates as a Suggestion
in the Business Messaging connector and sending a message with solely a
Suggestion is not supported. The Business Messaging client (CM.Text
nuget) doesn't support a text message with suggestion on the correct
level so we had to hack something to made it work. As a result, the
TextWithUrlStep was born.

Please note Please refrain from using this component, unless you
can't.

    steps:
      - !text_with_url
        id: subflow_event_tvgo_url_link
        textMessage: "Remek választás! Bővebb információért koppints ide:"
        url: "https://www.tvgo.hu/cikk/25890886_universal_filmek_felaron_a_tv_go_n_advent_3"
        urlLabel: "TVGO"
        mediaName: "figure%20skating.png"
        mediaUri: "https://d15k2d11r6t6rl.cloudfront.net/public/users/Integrators/371a907d-72a2-4e4e-8549-723bc6aba3dc/d7df6908-f9ac-41ac-91a5-f1e74e5a4085/1_TVGO_Link.JPG"
        mediaMimeType: "image/png"

Properties

  • textMessage The text that goes along with the rich link.
  • url The actual url to go to when the rich link is clicked.
  • urlLabel The label that comes with the url.
  • mediaName The name of the preview picture of the page where the
    link points to.
  • mediaUri The uri where the preview picture can be found.
  • mediaMimeType The mime type of the preview picture.

WebRequestStep

Object tag: !webrequest

A webrequest can be used to have the script-engine send or gather
information from an external webrequest. It requires the third party to support at least TLS 1.2.

If you use IP whitelisting, our IP address is 34.141.248.107.

The following applies for a WebRequestStep:

  • The webrequest is performed during script execution and might slow
    down script execution.
  • If the script execution needs information from the reply in the following steps, set waitForResponse to true. If you just want a fire-and-forget webhook scenario: set waitForResponse to false.
  • If the WebrequestStep fails (after 10 retries with an exponential backoff between 1 and 10 sec),
    the script continues, if configured, from the failPosition.
    steps:
      - !webrequest
        id: webrequest_step
        waitForResponse: true
        failPosition:
          flowId: "failedFlow"
          stepId: "TalkToAHuman"
        request:
          url: "https://some.cool.api.cm.com/coolapi/v1/resources/"
          method: POST
          timeout: 60
          headers:
            X-CM-PRODUCTTOKEN: "5c93c6e0-d13b-11e8-8b40-11086b70fb08"
          queryParameters:
            skip: 50
            take: 50
          body: |
           {
            "customer_data": {
            "first_name": "",
            "last_name": "",
            "email": "",
            "mobile": ""
           },
            "ticket_types": [
           {
             "uuid": "cc8632f8-6d17-4c48-a8a0-1acfa8a9130f",
             "amount": 
           }
           ]
           }
        response:
          extracts:
            - var: "order_id"
              source: "@body.json"
              selector: "order_id"

Properties

  • waitForResponse Should be set to 'true' if the script execution needs information from the reply in the following steps, otherwise 'false'.
  • failPosition Position to continue from when the webrequest
    failed
  • request Block containing all specific information about the
    request.
  • response Block containing configuration on what to do with the
    response.

Request properties

  • request.url The url for the request. Supports interpolating
    variables by enclosing them in .
  • request.method HTTP Method for the request.
  • request.headers Key-value collection to specify headers.
  • request.body The (json) body that goes with the request.
    Supports variable interpolation using .
  • request.timeout Any number, this value is ignored because of the addition of our exponential backoff. Removing it from the JSON will be done towards the future.

Response properties

  • response.extracts A collection of so-called extracts, that will
    enable pulling information from the response.
  • response.extracts.var The session variable name to store the
    extracted value.
  • response.extracts.source The source of the extract. One could
    specify the following options:
    • @body.json The response body, handled/casted as json. You
      can specify a json path query as 'selector'.
    • @body.xml The response body, handled/cased as xml. You can
      specify an xml path query as 'selector'.
    • @body.text The plain text value of the response body.
    • @status_code Numeric HTTP response code of the request.
    • @is_success Boolean indicating success or failure of the
      request.
    • @retries Number of times the request was retried.
  • response.extracts.selector The json/xml path query to perform on
    the response.

Scalar types

In case the response body contains only a scalar type then it's
possible to extract that value using the selector "."

    steps:
      - !webrequest
        id: webrequest_step
        waitForResponse: true
        failPosition:
          flowId: "failedFlow"
          stepId: "TalkToAHuman"
        request:
          url: "https://some.cool.api.cm.com/coolapi/v1/resources/"
          method: POST
          headers:
            X-CM-PRODUCTTOKEN: "5c93c6e0-d13b-11e8-8b40-11086b70fb08"
          queryParameters:
            skip: 50
            take: 50
          body: |
           {
            "customer_data": {
            "first_name": "",
            "last_name": "",
            "email": "",
            "mobile": ""
           },
            "ticket_types": [
           {
             "uuid": "cc8632f8-6d17-4c48-a8a0-1acfa8a9130f",
             "amount": 
           }
           ]
           }
        response:
          extracts:
            - var: "order_id"
              source: "@body.json"
              selector: "."

Type conversions

Type Value Becomes


boolean false "False"
boolean true "True"
null null ""
string any string same string value
int (i.e 1) "1"
float (i.e 1.01) "1.01"

WaitStep

Object tag: !wait

The wait step is used to wait a certain amount of time before continuing
the chat flow. This interval can be interrupted by sending a new start
sequence as defined in the entry step.

      - !wait 
        id: Wait-1
        actions: []
        clientActions: []
        interval: 30

Properties

  • interval Time to wait for (in seconds) before continuing the
    flow

CommandStep

Object tag: !command

The CommandStep is used to invoke a command.

      - !<!command> 
        id: Command-1
        actions: []
        clientActions: []
        name: Handover
        context:
          team: '10'

Properties

  • name The name of the command that should be invoked
  • context You can supply dictionary (key/value pairs) that will
    end up in the router-session and will travel along with the (router
    internal) RoutingMutated event, which will be available in the
    ConversationalRouter adapter for CustomerContact / BMProxy. As a
    result this context will be available to webcalls to CustomerContact
    and BMProxy. It is possible to use variables as values as displayed
    for 'var3'.

MenuStep

Object tag: !menu

The MenuStep is used as an aggregate of the steps you'd normally use
for asking the customer for feedback (text, listpicker or replybuttons),
waiting for the answer and doing logic based on that answer. This is
such a common pattern that using this step will save a lot of screen
space providing a better overview of the open flow.

The MenuStep uses an InputStep under water of which you can access the
input from the user in the context variable
'@session.menuStepId.UserInput' where you should substitute
'menuStepId' with the id of the MenuStep of which you want to use the
user's input.

      - !<!menu> 
        id: Menu-1
        actions: []
        clientActions: []
        displayType: Text
        header: header text
        interactiveMessageBody: ''
        buttonTitle: ''
        footer: footer text
        options:
          - key: '1'
            keyAliases:
              - een
              - one
            contentType: PlainText
            displayedText: '1: get in contact with a sales agent'
            cursor: sales-flow.Text-1
          - key: '2'
            keyAliases:
              - two
              - twee
            contentType: PlainText
            displayedText: '2: Get in contact with management'
            cursor: management-flow.Text-1
        fallback: fallback text
        timeoutInSeconds: '50'
        timeoutCursor: fallback.Text-1

Properties

  • displayType The visual representation you want the options to be
    displayed as. Possible options are text (all channels), listpicker
    (Apple Business Chat or WhatsApp) or reply buttons (WhatsApp)
  • header Small piece of text to display at the top. Will be a
    separate text message if the displayType is text
  • interactiveMessageBody Body of the visual representation when
    choosing listpicker or reply buttons. Mostly used for clarification
    of the provided options
  • buttonTitle Title of the button that opens up the listpicker
    (not applicable to other display types)
  • footer Small piece of text useful for concluding text about the
    options. Will be a separate text message if the displayType is text
  • fallback The text message that will be sent if none of the user
    input matches the options (only applicable to displayType text)
  • timeoutInSeconds Time to wait for user input before navigating
    to the location of the timeoutCursor (optional)
  • timeoutCursor The namespaced (concatenated) position in the
    script to go to when the input timeout is hit (optional)

Option properties

  • key Identifier/piece of text that should be matched by the
    user's input for the option to be selected
  • keyAliases Similar input that should also match this option
    (only applicable if displayType is text)
  • contentType Representation of option. Currently only supports
    text with a possible addition of an image in the future
  • displayedText The body of the option that's shown to the user
    with the selected displayType. This represents what they can select
    visually
  • cursor The namespaced (concatenated) position in the script to
    go to when the option is matched

ClientActions

Some channels like Apple Business Chat and RCS support so-called client
actions or suggestions (as they're called in Business Messaging slang).
These client actions will render as buttons or options in the app and
allow for easy replies, instant meeting requests and others. Below is an
example of a common scenario where a question is asked and one should
reply using one of the two reply buttons.

    steps:
      - !text
        id: question_hamburgers
        message: "Do you like hamburgers?"
        clientActions:
          - !reply
            label: "Yeah!"
            replyText: "YES"
          - !reply
            label: "Nope!"
            replyText: "NO"
      - !input
        id: question_hamburgers_input
        var: "LikesHamburgers"

Create Calendar Event

Object tag: !create_calendar_event

Use the Create Calendar Event client action to have option added to
instantly add a calendar event.

        clientActions:
          - !create_calendar_event
            label: "Option 1"
            replyText: "calendar_event_created"
            title: "Calendar Event Title"
            description: "Calendar Event Description"
            startTime: "2020-02-02T22:22:22Z"
            endTime: "2020-02-02T22:23:22Z"

Properties

  • label The text displayed on the button / option.
  • replyText The actual text to send back.
  • title Title of the window that shows the datepicker.
  • description Description to be displayed when using the
    datepicker
  • startTime Starting date/time of the calendar item.
  • endTime End date/time of the calendar item.

Dial

Object tag: !dial

With the Dial client action a button will be displayed that will call
the number you assign to it.

        clientActions:
          - !dial
            label: "Bel op!"
            replyText: "dialed"
            phoneNumber: "+31612345678"

Properties

  • label The text displayed on the button / option.
  • replyText The actual url text that is sent back.
  • phoneNumber The MSISDN to dial.

Open Url

Object tag: !open_url

This action will open a url.

        clientActions:
          - !open_url
            label: "Bel op!"
            replyText: "url_opened"
            uri: "http://www.cm.com"

Properties

  • label The text displayed on the button / option.
  • replyText The actual text to send back.
  • uri Web address to open.

Reply

Object tag: !reply

Can be used to create a set of fixed replies. Please note that the label
of the option can be different from the actual text being sent.

        clientActions:
          - !reply
            label: "Option 1"
            replyText: "option_1"

Properties

  • label The text displayed on the button / option.
  • replyText The text to send back.

View Location

Object tag: !view_location

Use the View Location client action to open a map interface to display
the location.

        clientActions:
          - !view_location
            label: "View Location of CM HQ"
            replyText: "view_location_clicked"
            latitude: 51.603719
            longitude: 4.770777
            locationLabel: "CM HQ"

Properties

  • label The text displayed on the button / option.
  • replyText The actual text that is sent back.
  • latitude Latitude of the location.
  • longitude Longitude of the location.
  • locationLabel Text displayed next to the location.

Actions (Deprecated)

Actions can be defined on a Step to let the script engine know to
perform some action, like calling a webhook or going to a specific part
of the script.

The following rules apply:

  • No guarantees will be given for the order in which actions run.
  • Exception on the rule above is that PositionalActions, like
    PositionAction and CursorAction, will be performed after all
    other types of actions.

Below is an example of common usage of an action (PositionAction) when
checking a menu choice.

    steps:
      - !input
        id: input_menuchoice_step
        var: "menuChoice"
      - !if
        id: menuChoice_equals_1
        var: "menuChoice"
        value: "1"
        actions:
          - !position
            flowId: menu_choice_1_flow
            stepId: some_step_in_flow

CursorAction (Work in Progress)

The CursorAction is a close relative of the PositionAction. The
difference is that a CursorAction works with a single property pointing
to a specific item in the script and the PositionAction does not.

Please note the following:

  • The dot '.' is reserved for concatenating (namespacing) of the
    cursor. Refrain from using a '.' in the 'id' of a Flow as well
    as a Step.
    steps:
      - !input
        id: input_menuchoice_step
        var: "menuChoice"
      - !if
        id: menuChoice_equals_1
        var: "menuChoice"
        value: "1"
        actions:
          - !cursor
            cursor: menu_choice_1_flow.some_step_in_flow

Properties

  • cursor The field actually holding the namespaced (concatenated)
    position in the script to go to.

PositionAction

The positionaction is the older relative of the CursorAction. The
PositionAction has separate properties to point to a Flow and a Step and
the CursorAction uses a single string.

Below is an example of a common usage for the PositionAction. Please
note
that the preferred way of pointing to a part of the script will
be the cursor, because it allows for more flexibility.

    steps:
      - !input
        id: input_menuchoice_step
        var: "menuChoice"
      - !if
        id: menuChoice_equals_1
        var: "menuChoice"
        value: "1"
        actions:
          - !position
            flowId: menu_choice_1_flow
            stepId: some_step_in_flow

Properties

  • flowId Id of the flow to go to.
  • stepId Id of the step (within the flow) to go to.

Session Variables

Session variables are name/value pairs that can be stored in a few ways.
First of all there are fixed/system variables, variables either obtained
by user input or processed by means of regular expressions.

Fixed/System variables

When a session starts the following system variables will be
automatically added to the session variables collection.

  • $startSequence This is the literal text that was sent to start
    the current session.
  • $conversationClientId This is the identification number
    (msisdn, apple chat id, etc) of the end-user.
  • $conversationClientIdNormalized Normalized (00) version of the
    conversationClientId
  • $conversationHostId This is the identification number of the
    party that hosts the chat.
  • $conversationClientName This is the identification name of the
    end-user (not supported by all parties).
  • $channel The channel that was used of the message that started
    the session.
  • $chatId Fixed hashed Guid of the combination of channel,
    conversationClientId and conversationHostId. Can be safely used for
    external communication from within the chatscript.

Obsolete

  • $recipient See conversationClientId
  • $chatIdGuid Implementation of $chatId when the latter was
    still the concatenation of
    'Channel#conversationClientId#conversationHostId'.

Dynamic Variables/System Functions

Dynamic variables are similar to Fixed/System variables, however, the
output of these variables is changeable. The use of parameters allows
the end-user to form the desired output. The following Dynamic variables
are available for use whenever a session is started:

$GetNow() Gets the current time according to the parameters. The
following parameters are supported:

  • TimeZone is required, and allows you to specify the TimeZone for which to get the time. You can use any timezone supported by the tz database.
  • Format is required, and allows you to specify the format to apply to the time. For example, using "yyyy-MM-dd hh:mm:ss" will get you the current year, month, day, hour, minute and seconds. All the
    possible formatting options can be found here.
  • Language is an optional third parameter, which allows you to specify the language to apply to the output. If you get the weekday and supply "it-IT", for example, you will get the weekday in Italian. You can see a list of supported language tags here. If you omit this value the output will default to "en-US".

An example of this would be getting the current date and time in the timezone of our HQ in Breda: $GetNow("Europe/Amsterdam", "yyyy-MM-dd hh:mm:ss").

It might also be helpful to get the current day. Let's make it more exciting by getting the italian variant: $GetNow("Europe/Amsterdam", "dddd", "it-IT")

Variables by input

When using an InputStep the literal value that is sent by the end-user
will be stored in the variable name as specified by the 'var'
property. For an example please see InputStep

Variables from regular expressions

It is also possible to extract variables from regular expressions when using an EntryStep or LogicStep with !regex condition. See the InputStep and LogicStep for more information and examples.