The ChatShipper Developer Hub

Welcome to the ChatShipper developer hub. You'll find comprehensive guides and documentation to help you start working with ChatShipper as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started

6. Workflows

6.1 Overview

Workflows store and execute rules, emit events, and maintain the state needed to route queued conversations to user channels. Workflows are executed using a powerful, lightweight rules engine.

The purpose of a workflow is to figure out which Channels should be notified when a conversation enters the queued state.

Here's how the process works:

1. Conversation gets queued

A conversation gets into the queued state when:

  • A new contact sends the very first message into ChatShipper, or
  • an agent closes an active conversation that needs to be requeued, or
  • a closed conversation receives the /enqueue command from a backend automation.

A closed conversation gets (re)queued automatically when:

  • the contact is online, and
  • he/she sends (or has sent) the last message in the conversation.

2. Workflows (of own organization and ancestors) run

Whenever a conversation gets queued, all workflows of the owning organization are run. In addition, all workflows of any parent organizations are run that are not limited to exclude the conversations's organization (by specifying applicable organizations and organization tags for the workflow).

Any workflow of an ancestor organization may be active for all its organizations, or limited to a selected set of organizations and/or, more dynamically, a set of organization groups. In the above diagram, the workflows of "MCC" and "Acme Corp" that were activated, may have been set up specifically to handle "Acme Benelux" or organization groups that Acme Benelux is a member of.

If an organization does not have any workflows defined, all organization channels will be notified of the conversation.

3. For each workflow, any matching rules trigger events

A workflow consist of a list of rules that are evaluated in order of priority. Rules are composed of two components: conditions and events. Conditions are a set of requirements that must be met to trigger the rule's event. The event represents one or more Channels or Users that should be notified of the queued conversation.

Running a workflow executes the rules, and fires off events for rules for which conditions were met.

4. Resulting events notify agent channels

When a workflow runs, zero or more rules with matching conditions may trigger. For each rule the triggered event will notify channels or users of the queued conversation.


6.2 Walkthrough

1. Create a workflow

The MCC in our examples uses a workflow that handles all conversations for organizations in the Automotive group. Our MCC has chosen to have Channels for each conversation category, in addition to a Switchboard channel that receives notifications for all uncategorized queued conversations.

Let's create this workflow, limit it to apply only to organizations in the Automotive Organization Group, and include a rule for the Switchboard channel.

Request: POST /v2/workflows

{
    "_id": "592f5a95263fba5beb623f66",
    "name": "Automotive - Generic",
    "organizationTags": ["5917af88c63934459825deef"],
    "rules": [
      {
        "priority": 1,
        "event": {
          "type": "notify",
          "params": {
            "name": "Uncategorized goes to Switchboard",
            "channels": ["cccbbb000000000000000bbb"],
            "delay": 20,
            "isLastRule": true
          }
        },
        "conditions": {
          "all": [
            {
              "fact": "conversation",
              "path": ".category",
              "operator": "equal",
              "value": null
            }
          ]
        }
      }
    ]
}

The only rule in this workflow only gets triggered when the conversation category has not yet been set; the Switchboard agent is supposed to engage the consumer, set the category and re-queue the conversation.

2. Add a Rule

Let's add a rule to handle conversations in the "Used Car" category, and route them to the designated channel (by posting to the rules collection in the workflow):

Request: POST /v2/workflows/592f5a95263fba5beb623f66/rules

{
    "priority": 1,
    "event": {
      "type": "notify",
      "params": {
        "name": "Category 'Used Car' goes to channel 'Used Car'",
        "channels": ["cccbbb000000000000000bbb"],
        "delay": 20,
        "isLastRule": true
      }
    },
    "conditions": {
      "all": [
        {
          "fact": "conversation",
          "path": ".category",
          "operator": "equal",
          "value": "Used Car"
        }
      ]
    }
}

Any queued conversation with the category set to "Used Car" will get the agents subscribing to this dedicated channel notified.


6.3 Rules

A rule contains a set of conditions and a single event. When the workflow is run, each rule condition is evaluated. If the results are truthy, the rule's event is triggered.

A rule has the following properties:

  • conditions : [Object] Rule conditions object
  • event : [Object] Sets the event emitted whenever the rule passes. Event objects must have a type and a params property.
  • priority : [Number, default 1] Dictates when an immediate rule should be run, relative to other immediate rules. Higher priority rules are run before lower priority rules (priority 2 will run before priority 1). Rules with the same priority are run in parallel. Priority must be a positive, non-zero integer. Delayed rules (event.params.delay greater than zero) will have its priority ignored, and will run in order of increasing delay.

Event

A rule's event represents either the target Channel(s) and/or User(s) that should be notified if the rule is triggered. An event has a type and a params object; the only type currently supported is notify, but we may support other event types in the future.

notify

This event, when triggered, notifies available channels and users.

Request: PATCH /v2/workflows/5931b5259fe4f538c1e65a33/rules/5931b5259fe4f538c1e65a35

  {
    "event": {
      "type": "notify",
      "params": {
        "name": "Sales",
        "users": [],
        "channels": ["592e17099dda7550664a2542"],
        "delay": 0,
        "isLastRule": false
      }
    }
  }

The params object for the notify event may have the following properties:

  • name : [String] Rule/event name to display in admin UIs.
  • channels : [Array(ChannelID)] The Channel IDs that should be notified on this event.
  • users : [Array(UserID)] Any Users that should be notified directly, irrespective of any channel subscriptions.
  • delay : [Number, default 0] Number of seconds to wait before processing the event and notifying the Channel. Delay must be a positive-or-zero integer.
  • isLastRule : [Boolean, default false] Setting this to true skips processing any further rules.

All rules evaluate immediately, irrespective of delay. When a rule is triggered (conditions match) and the event is emitted, the target channel is notified if the conversation is still in state queued (not accepted by / assigned to an agent yet) at the moment the delay times out.

The delay is only applied if any previous rules succesfully delivered the conversation; if no Channels were notified yet, the event.delay is bypassed and the target channel is notified immediately.

If the channel has no active subscribers, the rule will be skipped. However, the channel ID will be stored in the conversation channelsOffline list: any agents subscribing to the channel from that point on will still receive a notification while the conversation is in the queued state.

If the channel does have active subscribers, it has now been notified (possibly after delay seconds), and the workflow will stop running if isLastRule is true, or process the next rule otherwise.


6.4 Rule Conditions

Conditions are sets of requirements that must be met to trigger the rule's event. Rule conditions are a combination of facts, operators, and values that determine whether the rule is a success or a failure.

The simplest form of a condition consists of a fact, an operator, and a value. When the workflow runs, the operator is used to compare the fact against the value.

Boolean expressions: all and any

Each rule's conditions must have either an all or an any operator at its root, containing an array of conditions. The all operator specifies that all conditions contained within must be truthy for the rule to be considered a success. The any operator only requires one condition to be truthy for the rule to succeed.

All:

  conditions: {
    all: [
      { /* condition 1 */ },
      { /* condition 2 */ },
      { /* condition n */ },
    ]
  }

Any:

  conditions: {
    any: [
      { /* condition 1 */ },
      { /* condition 2 */ },
      { /* condition n */ },
      {
        all: [ /* more conditions */ ]
      }
    ]
  }

Notice in the second example how all and any can be nested within one another to produce complex boolean expressions.


Facts

Facts and paths are methods or constants registered with the engine prior to runtime and referenced within rule conditions. When evaluating the conditions ChatShipper will fill in the fact attributes with appropriate values. As rule conditions are evaluated during runtime, they retrieve fact values at fact paths dynamically and use the condition operator to compare the fact result with the condition value.

Following is the list of supported facts and paths.

Fact Paths
conversation meta, category, categoryIndex, language
message meta, text, touchpoint
contact meta, email, worksFor, address
organization id, meta, country, industry, locale, tags
forms <form name>, <form id>, category<categoryIndex>
results names, forms, categories, categoryIndexes
context process, currentTime, currentHour, currentMin, dayOfWeek

Fact: conversation

The conversation is the conversation being queued. A typical use case is routing based on some conversation state variable set by a bot:

{
    "fact": "conversation",
    "path": ".meta.wasGreeted",
    "operator": "notEqual",
    "value": true
}

You can also route based on the conversation category (as previously set by an agent or bot) or language (as detected from contact messages); example:

{
    "fact": "conversation",
    "path": ".category",
    "operator": "in",
    "value": ["Used Car", "New Car"]
}

Fact: message

The message is the last message from the consumer. As an example, you can route based on the medium the consumer used to send the message; to match either Facebook Messenger or WhatsApp, use:

{
    "fact": "message",
    "path": ".touchpoint",
    "operator": "in",
    "value": ["messenger", "whatsapp"]
}

You can route notifications to certain channels by matching on signal words in the contact's message:

{
    "fact": "message",
    "path": ".text",
    "operator": "match",
    "value": "inruil"
}

Another typical use case is routing based on meta variables, as provided by the integration. For example, the following conditions block would match on live chat started from pages on the http://acme.de/supercar or https://www.acme.com/supercar/speed websites, and would also match if the message.meta.url is not specified or has on value:

"any": [
    {
      "fact": "message",
      "path": ".meta.url",
      "operator": "pattern",
      "value": "http(s)://($subdomain.)acme.$tld(:$port)/supercar(/*)"
    }, {
      "fact": "message",
      "path": ".meta.url",
      "operator": "defined",
      "value": false
    }, {
      "fact": "message",
      "path": ".meta.url",
      "operator": "equal",
      "value": null
    }
]

Fact: contact

The consumer's profile is represented by the contact fact object. As an example, you can route contacts known to live in New York differently than the rest of the world:

{
    "fact": "contact",
    "path": ".address.city",
    "operator": "equal",
    "value": "New York"
}

Fact: organization

The organization is the organization on behalf of which the conversation is conducted.

A condition matching conversations for any organization in the "Automobiles & Parts" industry would look like:

{
    "fact": "organization",
    "path": ".industry",
    "operator": "equal",
    "value": "3300"
}

To match on an organization's resource sharing tag you could use a condition similar to:

{
    "fact": "organization",
    "path": ".tags",
    "operator": "contains",
    "value": "nl-aut-retail"
}

Fact: forms

Channels and users can be targeted in workflows based on a form field value of any form active in the conversation. This is most useful with static forms, but also possible with regular topic forms (if they're active).

The fact object rule conditions are matched against, exists of values objects for static forms (keyed by name and form ID), and nested values objects for topic forms designated by the word 'category' appended by the category index.

As an example, here's what the fact object looks like for a conversation with a static form named 'Own Car' and a topic form called 'Test Drive' that's active for the first category:

    "forms": {
        "Own Car": {
            "brand": "bmw",
            "model": "5"
        },
        "5cfef6dbb9ba8733ad946e2b": {
            "brand": "bmw",
            "model": "5"
        },
        "category0": {
            "Test Drive": {
                "brand": "mercedes"
            },
            "5c785defe8565165be1c4f66": {
                "brand": "mercedes"
            }
        }
    }

When matching rules for this conversation, all of the following conditions would evaluate to true. These two conditions would match the static form:

{
    "fact": "forms",
    "path": ".Own Car.brand",
    "operator": "equal",
    "value": "bmw"
}
{
    "fact": "forms",
    "path": ".5cfef6dbb9ba8733ad946e2b.brand",
    "operator": "equal",
    "value": "bmw"
}

These two conditions would match the topic form:

{
    "fact": "forms",
    "path": ".category0.Test Drive.brand",
    "operator": "equal",
    "value": "mercedes"
}
{
    "fact": "forms",
    "path": ".category0.5c785defe8565165be1c4f66.brand",
    "operator": "equal",
    "value": "mercedes"
}

Fact: results

The results fact and its paths lets you check for the existence of a completed result. It is a mapping of conversation.results flattened into an object containing lists of results properties, keyed by names, forms, categories and categoryIndexes.

After processing the "Test Drive" topic form in the previous example into a result, some matching conditions for existence check of the Test Drive result would be:

{
    "fact": "results",
    "path": ".names",
    "operator": "contains",
    "value": "Test Drive"
}
{
    "fact": "results",
    "path": ".forms",
    "operator": "contains",
    "value": "5c785defe8565165be1c4f66"
}

Fact: context

The context object represents a few runtime variables:

  • context.process: This attribute is always the number 1, for easy truthy conditions.
  • context.currentTime: This attribute contains current time as integer in HHMM (military) format with the time represented in 24hr clock in UTC.
  • context.currentHour: This attribute contains current hour as string in HH formt with hour represented in 24hr clock in UTC.
  • context.currentMin: This attribute contains current minute with time represented in UTC format.
  • context.dayOfWeek: This attribute contains the day of the week as three-letter string in time represented in UTC format, according to the following table:
Day of the Week context.dayOfWeek
Monday Mon
Tuesday Tue
Wednesday Wed
Thursday Thu
Friday Fri
Saturday Sat
Sunday Sun

The following condition is always true (context.process has a fixed value of 1 for this purpose):

{
    "fact": "context",
    "path": ".process",
    "operator": "equal",
    "value": 1
}

For matching time-based conditions, see the full "Office Hours" example below.


Operators

Each rule condition must begin with a boolean operator(all or any) at its root.

The operator compares the value returned by the fact to what is stored in the value property. If the result is truthy, the condition passes.

Generic operators:

-defined - fact must be present at path and specified (may be null)

String and Numeric operators:

  • equal - fact must equal value
  • notEqual - fact must not equal value
  • in - fact must be included in value (an array)
  • notIn - fact must not be included in value (an array)
  • match - fact must match value (a regular expression)
  • notMatch - fact must match value (a regular expression)
  • pattern - fact must match value (a url pattern)
  • noPattern - fact must match value (a url pattern)

The first two operators use strict equality (===) and inequality (!==)

Numeric operators:

  • lessThan - fact must be less than value
  • lessThanInclusive- fact must be less than or equal to value
  • greaterThan - fact must be greater than value
  • greaterThanInclusive- fact must be greater than or equal to value
  • between - fact must be between value (an array of 2 elements)
  • notBetween - fact must not be between value (an array of 2 elements)

Array operators:

  • contains - fact (an array) must include value
  • doesNotContain - fact (an array) must not include value

6.5 Rule Examples

Example: Office Hours

In this example we are checking for different open and closing hours based on day of the week to place conversations into appropriate Channels.

Request: POST /v2/workflows/5931b5259fe4f538c1e65a33/rules

{
    "priority": 1,
    "event": {
      "type": "notify",
      "params": {
        "name": "Office Hours",
        "channels": ["cccbbb000000000000000bbb"]
      }
    },
    "conditions": {
      "any": [
        {
          "all": [
            {
              "fact": "context",
              "path": ".dayOfWeek",
              "operator": "in",
              "value": ["Mon", "Tue", "Thu"]
            },
            {
              "fact": "context",
              "path": ".currentTime",
              "operator": "between",
              "value": [800, 1730]
            }
          ]
        },
        {
          "all": [
            {
              "fact": "context",
              "path": ".dayOfWeek",
              "operator": "in",
              "value": ["Wed", "Fri"]
            },
            {
              "fact": "context",
              "path": ".currentTime",
              "operator": "between",
              "value": [900, 1830]
            }
          ]
        }
      ]
    }
}

A rule with these conditions will trigger on Mondays, Tuesdays and Thursdays between 08:00am and 05:30pm, and Wednesdays and Fridays between 09:00am and 06:30pm. Outside these office hours the target Channel will not be notified.


6.6 Testing

Fetching all workflows that run for an organization

When a contact message is sent into a closed conversation, several workflows (owned by the organization itself and its parents) may be started in parallel. To fetch a list of all workflows kicked off for an organization, make a request like this:

Request: GET /v2/organizations/5a4ce0418e84ea7053d8e4e7/workflows

[
    ...workflow of organization...
    ...workflow of parent organization...
    ...workflow of parent's parent organization...
]

Any query parameters (filtering, sorting, pagination) will be ignored, the request will always return a full list of all workflows that run on an inbound contact message for the organization.

Testing workflows and rules

You can test workflows and individual rules by POSTing a mock facts object to their respective endpoint; a list of matching rule events will be returned.

Here's a simulation of a consumer from Wassenaar, that is visiting www.acme.de/supercar/features on a Wednesday at 5:15pm, asking an organization with two bots about "inruilen" after two channels were already notified:

Request: POST /v2/workflows/5931b5259fe4f538c1e65a33
Request: POST /v2/workflows/5931b5259fe4f538c1e65a33/rules/5931b5259fe4f538c1e65a35

{
    "organization": {
        "commands": ["inruil", "vr"]
    },
    "conversation": {
        "category": "Used Car",
        "contactStatus": "online",
        "channels": ["a","b"]
    },
    "message": {
        "meta": {
            "url": "https://www.acme.de/supercar/features"
        },
        "text": "Kan ik mijn auto inruilen?",
        "touchpoint": "web"
    },
    "contact": {
        "address": {
            "city": "Wassenaar"
        }
    },
    "context": {
        "currentTime": 1715,
        "dayOfWeek": "Wed"
    }
}

Response: 200 OK

[
  {
    "type": "notify",
    "params": {
      "name": "Supercar",
      "users": ["58ffcd98fcbd323ba6b4632b", "591a7fa6560320275eafbdcb"],
      "delay": 0,
      "isLastRule": false
    }
  }
]

The test response contains a list of events for the rules that triggered: a non-empty list indicates a match.


What's Next

Now that we've covered account setup, let's move on with the Messaging Guide.

1. Getting Started

6. Workflows


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.