EZ Texting Workflows Schema

$schema: https://json-schema.org/draft/2020-12/schema
$defs:
  ".condition.And":
    type: object
    properties:
      and:
        description: List of conditions to check against
        type: array
        items:
          anyOf:
          - $ref: "#/$defs/.condition.And"
          - $ref: "#/$defs/.condition.Or"
          - $ref: "#/$defs/.condition.Not"
          - $ref: "#/$defs/.condition.JS"
          - $ref: "#/$defs/.condition.Variable"
          - $ref: "#/$defs/.condition.Operation"
    description: |
      Logical "and" to check against the conditions provided in the children. Must have at least 2 conditions.
    additionalProperties: false
    examples:
    - example-description: will be true if all of the js and variable condition evaluates to true
      and:
      - js: |
          some code here
      - op: eq
        value: check-against-this-value
        variable: check-against-this-variable
  ".condition.JS":
    type: object
    properties:
      js:
        type: string
        description: Custom java script to evaluate to calculate if the value is true
    description: |
      Custom java script to evaluate to calculate if the value is true.
      To succeed must return true boolean or any of the strings: 'true', 'on', 'y', 't' or 'yes'. Otherwise will evaluate to false.
    additionalProperties: false
    examples:
    - example-description: will evaluate to true
      js: |
        true
    - example-description: will evaluate to true
      js: |
        '12356'.length == 5
    - example-description: will evaluate based on the value in contact custom field
      js: |
        contact.vipClient
  ".condition.Not":
    type: object
    properties:
      not:
        anyOf:
        - $ref: "#/$defs/.condition.And"
          description: Condition to negate
        - $ref: "#/$defs/.condition.Or"
          description: Condition to negate
        - $ref: "#/$defs/.condition.Not"
          description: Condition to negate
        - $ref: "#/$defs/.condition.JS"
          description: Condition to negate
        - $ref: "#/$defs/.condition.Variable"
          description: Condition to negate
        - $ref: "#/$defs/.condition.Operation"
          description: Condition to negate
    description: |
      Negates the evaluation result of the child condition.
    additionalProperties: false
    examples:
    - example-description: will evaluate to false as a result
      not:
        js: |
          true
  ".condition.Operation":
    type: object
    properties:
      dataType:
        $ref: "#/$defs/OperationDataType"
        description: The type of the data the operation is working with
      operation:
        $ref: "#/$defs/OperationType"
        description: Operation to perform on the provided input
      value:
        type: string
        description: the value to compare with
    description: |
      The operation to perform on the provided input. Will evaluate to true or false based on the input
    additionalProperties: false
    examples: []
  ".condition.Or":
    type: object
    properties:
      or:
        description: List of conditions to check against
        type: array
        items:
          anyOf:
          - $ref: "#/$defs/.condition.And"
          - $ref: "#/$defs/.condition.Or"
          - $ref: "#/$defs/.condition.Not"
          - $ref: "#/$defs/.condition.JS"
          - $ref: "#/$defs/.condition.Variable"
          - $ref: "#/$defs/.condition.Operation"
    description: |
      Logical "or" to check against the conditions provided in the children. Must have at least 2 conditions.
    additionalProperties: false
    examples:
    - example-description: will be true if one of the js or variable condition evaluates to true
      or:
      - js: |
          some code here
      - op: eq
        value: check-against-this-value
        variable: check-against-this-variable
  ".condition.Variable":
    type: object
    properties:
      dataType:
        $ref: "#/$defs/OperationDataType"
        description: The type of the data the operation is working with
      op:
        $ref: "#/$defs/OperationType"
        description: Operation to perform on the variable
      value:
        type: string
        description: "Value to check against. Optional for some types of operations, like 'exists'"
      variable:
        type: string
        description: Name of the variable to check against
        minLength: 1
        pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
    required:
    - op
    - variable
    description: |
      Variable condition to check against.
      Takes a variable and checks operation on that.
    additionalProperties: false
    examples:
    - example-description: "will evaluate to true, assuming \"theVariable\" variable has text 'hello world'"
      op: contains
      dataType: text
      value: world
      variable: theVariable
    - example-description: "will evaluate to false, assuming \"theVariable\" variable has text 'hello world'"
      op: eq
      dataType: text
      value: world
      variable: theVariable
    - example-description: "will evaluate to true, assuming \"theDateVariable\" variable has date value of '2025-01-01T15:49:51'"
      op: gt
      dataType: date
      value: 2024-12-01T05:39:00
      variable: theDateVariable
  ".configuration.action.Delay":
    type: object
    properties:
      amount:
        type: integer
        description: The amount of units to delay execution for
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      units:
        $ref: "#/$defs/DelayUnit"
        description: Units to delay execution for
      waitForDate:
        examples:
        - 2030-12-31
        description: Specific date to wait for
        additionalProperties: false
        type: string
        format: date
      waitForDay:
        $ref: "#/$defs/DayOfWeek"
        description: Day of week to wait for
      waitForTime:
        examples:
        - 23:59:59
        description: Specific time to wait for
        additionalProperties: false
        type: string
        format: time
      type:
        const: .configuration.action.Delay
    description: |
      Delay the execution for specified configurable time.

      One can specify one of the setting: units, waitForDay or waitForDate.
      Additional setting waitForTime can be added to the above.

      The calculations will be done in account time zone, specified in settings.
    additionalProperties: false
    examples:
    - example-description: wait for 3 days AND until 14:00
      type: .configuration.action.Delay
      transitionTo: ResumeExecutionNode
      amount: 3
      units: DAY
      waitForTime: 14:00:00
    - example-description: wait until specified date and 3 pm
      type: .configuration.action.Delay
      transitionTo: ResumeExecutionNode
      waitForDate: 2025-12-31
      waitForTime: 15:00:00
    - example-description: wait until Monday at 5 pm
      type: .configuration.action.Delay
      transitionTo: ResumeExecutionNode
      waitForDay: MONDAY
      waitForTime: 17:00:00
  ".configuration.action.DeleteContact":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.action.DeleteContact
    description: |
      Deletes a contact from account with all the values.
      Note: even after deleting workflow can still resume for a phone number.
    additionalProperties: false
    examples:
    - example-description: deletes a contact and will resume execution to the next node named "The next execution"
      type: .configuration.action.DeleteContact
      transitionTo: The next execution
  ".configuration.action.HttpRequest":
    type: object
    properties:
      errorTransition:
        type: string
        description: Next node name when execution fails
      headers:
        $ref: "#/$defs/Map(String,String)"
        description: Headers to send along with request
      jsonKeyValues:
        $ref: "#/$defs/JsonNode"
        description: Json key values to use as body object to send. Supports variable replacements in values
      method:
        $ref: "#/$defs/Method"
        description: HTTP method to use
      requestBodyVariable:
        type: string
        description: Request body variable to use to send body as. Will be sent as String entity.
      successTransition:
        type: string
        description: Next node name when execution succeeds
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      url:
        type: string
        description: Url to send request to. Supports variable replacements
      type:
        const: .configuration.action.HttpRequest
    description: |
      Perform http request to an external endpoint and evaluate expression based on the response.
      Can variables based on the execution result.
      The body of the request will be sent only for HTTP calls that support that by specification, otherwise it will be ignored.
      Use requestBodyVariable or jsonKeyValues to populate the body that the request will be sent with.
      Passes "responseBody" variable to expression to evaluate the result on.
    additionalProperties: false
    examples:
    - example-description: |-
        Perform GET request and extract isVipClient from response, and set it to the vipClient variable.
        Transition to next node named "Next Node"
      type: .configuration.action.HttpRequest
      transitionTo: Next Node - Deprecated for HttpRequest
      method: GET
      url: "https://example.endpoint/get-info-about?phoneNumber=${contact.phoneNumber}"
      headers:
        Accept: application/json
        Custom-Header: test
      requestBodyVariable: theVariableThatContainsBodyToSend
      variable: vipClient
      expression: |
        JSON.parse(responseBody).isVipClient
      successTransition: Next node when execution succeeds
      errorTransition: Next node when execution fails
    - example-description: example shows usage of jsonKeyValues replacements - vipClient is populated with field of the contact.
      type: .configuration.action.HttpRequest
      transitionTo: Next Node - Deprecated for HttpRequest
      method: POST
      url: "https://example.endpoint/update-info-about?phoneNumber=${contact.phoneNumber}"
      headers:
        Accept: application/json
        Custom-Header: test
      jsonKeyValues:
        vipClient: "${contact.isVipClient}"
        info: hello!
      variable: vipClient
      expression: |
        JSON.parse(responseBody).isVipClient
      successTransition: Next node when execution succeeds
      errorTransition: Next node when execution fails
    allOf:
    - type: object
      properties:
        expression:
          type: string
          description: Expression to evaluate the value to set. Supports JavaScript.
        variable:
          type: string
          description: Name of the variable to set the result of the evaluation of the expression. May be empty if the result is returning map or object with key values.
          pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      description: combination of variable with expression to reuse in configurations that require that
      additionalProperties: false
  ".configuration.action.OptOut":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.action.OptOut
    description: |
      Opts out the contact from the further communication.
      Note: you can still resume execution. For example to do some http request to make sure you update the contact info on third party side.
    additionalProperties: false
    examples: []
  ".configuration.action.SendMessage":
    type: object
    properties:
      campaignId:
        type:
        - string
        - number
        description: Campaign id that you'll see messages on the dashboard. Auto generated upon first save.
        readOnly: true
      containsSuspiciousWords:
        type: boolean
        description: "An indicator if this message contains suspicious words. If so, you'll have to wait until we work it out or contact customer support to unblock it."
        readOnly: true
      fileId:
        type:
        - string
        - number
        description: The file id to send.
      message:
        type: string
        description: The message text to send. Supports variable replacements. Can use emojis ?
      messageType:
        $ref: "#/$defs/MessageType"
        description: "Type of the message to send. Note: setting this to MMS doesn't guarantee it will be sent as MMS, since some of the carriers doesn't support it. It may be transformed to SMS automatically."
      subject:
        type: string
        description: Subject of the message
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      variable:
        type: string
        description: the variable name to use to set the resulting delivery state and delivery category to
        pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      type:
        const: .configuration.action.SendMessage
    description: |
      Sends a message to the contact supporting variable replacements from the instance execution.
    additionalProperties: false
    examples:
    - example-description: "the variables will be saved into sendMessage variable for the execution and can be later accessed like: sendMessage.deliveryState or sendMessage.deliveryCategory"
      type: .configuration.action.SendMessage
      transitionTo: SomeOtherNode
      subject: Your Company Name
      messageType: MMS
      message: |
        Hello, very nice to see you're using workflows from EzTexting! ?
        The message you're composing supports variable replacements.
        You can use same notation as in sending group texts like ${FirstName} or ${URL=https://example.com}
        or even variable replacements with workflow style: ${contact.firstName} or even with space ${contact.custom Field}
      fileId: 100
      campaignId: 123456789
      containsSuspiciousWords: false
      variable: sendMessage
  ".configuration.action.SetVariable":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.action.SetVariable
    description: |
      Sets a variable for the current instance during its execution.
      Use this to run custom JavaScript and assign the returned value to an instance variable in flow execution context.
      The returned result can be a string, number, date, boolean, or an object with properties.
    additionalProperties: false
    examples:
    - example-description: Assigns a static numerical value to the variable.
      type: .configuration.action.SetVariable
      transitionTo: OtherNode
      variable: numericVariableName
      expression: |
        42
    - example-description: Assigns a string literal to the variable.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: strGreeting
      expression: |
        'Hello, world!'
    - example-description: Calculates a simple math expression and assigns the result.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: numericVariableName
      expression: |
        (2 + 5) * 10
    - example-description: |-
        Calculates a math expression using variables from the execution context and assigns the result.
        For example, given a context variable TWO=2, the expression (TWO + 5) * 10 would result in 70.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: numericVariableName
      expression: |
        (TWO + 5) * 10
    - example-description: |-
        Constructs a new object by reusing variables from previous steps using JavaScript object notation.
        The resulting object can also be reused in subsequent steps.
        In this example, it maps the contact's phone number, which is stored in the 'contact' variable as 'phoneNumber' property, to a key 'theValueFromPreviousSteps' in the resulting object.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: evaluateToSomeMap
      expression: |
        ({greeting: 'Hello, world!', e: 2.71828, pi: Math.PI, theValueFromPreviousSteps: contact.phoneNumber})
    - example-description: |-
        Evaluates an expression using values from previous steps.
        In this case, it gets the length of a phone number for the contact.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: phoneNumberLength
      expression: |
        contact.phoneNumber.length
    - example-description: |-
        Evaluates a multiline expression using values from previous steps.
        In this case, it converts a phone number retrieved from 'store.phoneNumber' context variable to MSISDN.
      type: .configuration.action.SetVariable
      transitionTo: Send Other Message
      variable: phoneNumberLength
      expression: |
        const phoneToMSISDN = (phone) => {
           if (phone.startsWith("+")) return phone;
           return "+" + phone;
        };
        phoneToMSISDN(store.phoneNumber);
    allOf:
    - type: object
      properties:
        expression:
          type: string
          description: Expression to evaluate the value to set. Supports JavaScript.
        variable:
          type: string
          description: Name of the variable to set the result of the evaluation of the expression. May be empty if the result is returning map or object with key values.
          pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      description: combination of variable with expression to reuse in configurations that require that
      additionalProperties: false
  ".configuration.action.UpdateContact":
    type: object
    properties:
      fieldExpressions:
        description: update a field with an expression value
        type: array
        items:
          $ref: "#/$defs/FieldExpression"
      listIds:
        description: contact list IDs to add/remove
        type: array
        items:
          type:
          - string
          - number
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      updateContactType:
        $ref: "#/$defs/UpdateContactType"
        description: update a field or contact groups
      type:
        const: .configuration.action.UpdateContact
    description: |
      Updates a contact's groups or field values.
      Performs one of the following actions:
      ADD_TO_GROUPS adds a contact to the specified groups,
      REMOVE_FROM_GROUPS removes a contact from the specified groups,
      UPDATE_FIELD update a contact's field value
      Note: phoneNumber is not allowed to be updated by the workflow.
    additionalProperties: false
    examples:
    - example-description: updates a contact's groups and move to the next node
      type: .configuration.action.UpdateContact
      transitionTo: The next execution
      listIds:
      - 123
      updateContactType: ADD_TO_GROUPS
    - example-description: updates a contact's field value and move to the next node
      type: .configuration.action.UpdateContact
      transitionTo: The next execution
      fieldExpressions:
      - fieldName: custom1
        expression: |
          ${myReply.messageText}
      updateContactType: UPDATE_FIELD
  ".configuration.condition.If":
    type: object
    properties:
      condition:
        anyOf:
        - $ref: "#/$defs/.condition.And"
          description: condition to evaluate against to determine to which branch to go
        - $ref: "#/$defs/.condition.Or"
          description: condition to evaluate against to determine to which branch to go
        - $ref: "#/$defs/.condition.Not"
          description: condition to evaluate against to determine to which branch to go
        - $ref: "#/$defs/.condition.JS"
          description: condition to evaluate against to determine to which branch to go
        - $ref: "#/$defs/.condition.Variable"
          description: condition to evaluate against to determine to which branch to go
        - $ref: "#/$defs/.condition.Operation"
          description: condition to evaluate against to determine to which branch to go
      falseTransition:
        type: string
        description: the name of the node that will be executed if condition evaluates to false
      transitions:
        description: the first node in the list whose condition evaluates to true will be executed
        type: array
        items:
          $ref: "#/$defs/Transition"
      trueTransition:
        type: string
        description: the name of the node that will be executed if condition evaluates to true
      type:
        const: .configuration.condition.If
    description: |
      Branch the workflow based on some condition.
      If condition evaluates to true then "true" node will be executed next, "false" node will execute otherwise.
    additionalProperties: false
    examples:
    - example-description: |-
        old style - will be removed soon
        based on the previously set variable (or contact custom field) we can branch the workflow. In this use case we're branching vip clients to specific scenario
      type: .configuration.condition.If
      trueTransition: NextTrueNode
      falseTransition: NextFalseNode
      condition:
        js: |
          contact.vipClient
    - example-description: |-
        old style - will be removed soon
        branching based on the date, we'll make sure customers will go other branch after some date
      type: .configuration.condition.If
      trueTransition: After 2030 Branch
      falseTransition: Before 2030 Branch
      condition:
        js: |
          new Date().getYear() > 2030
    - example-description: |-
        old style - will be removed soon
        branching based on multiple variables
      type: .configuration.condition.If
      trueTransition: After 2030 Branch
      falseTransition: Before 2030 Branch
      condition:
        and:
        - or:
          - js: |
              new Date().getYear() > 2030
          - op: eq
            value: value
            variable: variableName
        - js: |
            contact.vipClient
    - example-description: based on the previously set variable (or contact custom field) we can branch the workflow. In this use case we're branching vip clients to specific scenario
      type: .configuration.condition.If
      transitions:
      - name: VIP client
        condition:
          js: |
            contact.vipClient
        transitionTo: NextTrueNode
      falseTransition: NextFalseNode
    - example-description: "branching based on the date, we'll make sure customers will go other branch after some date"
      type: .configuration.condition.If
      transitions:
      - name: 2030
        condition:
          js: |
            new Date().getYear() > 2030
        transitionTo: After 2030 Branch
      falseTransition: Before 2030 Branch
    - example-description: branching based on multiple variables
      type: .configuration.condition.If
      transitions:
      - name: 2030
        condition:
          and:
          - or:
            - js: |
                new Date().getYear() > 2030
            - op: eq
              value: value
              variable: variableName
          - js: |
              contact.vipClient
        transitionTo: After 2030 Branch
      falseTransition: Before 2030 Branch
    - example-description: multiple branches
      type: .configuration.condition.If
      transitions:
      - name: 2030
        condition:
          js: |
            new Date().getYear() > 2030
        transitionTo: After 2030 Branch
      - name: VIP
        condition:
          js: |
            contact.vipClient
        transitionTo: Vip Client Branch
      falseTransition: New Client Branch
  ".configuration.condition.InList":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.condition.InList
    description: |
      Checks if the contact is in the list and branch based on the result.

      This node is not currently supported. Stay tuned.
    additionalProperties: false
  ".configuration.condition.OptOut":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.condition.OptOut
    description: |
      Checks if the contact is opted out.

      This node is not currently supported. Stay tuned.
    additionalProperties: false
  ".configuration.condition.RandomSplit":
    type: object
    properties:
      buckets:
        description: A list of named ranges to branch contact based on the random value
        type: array
        items:
          $ref: "#/$defs/.configuration.condition.RandomSplit$NamedRange"
      type:
        const: .configuration.condition.RandomSplit
    description: |
      Branch the workflow based random probability.

      Specify a range of probabilities to branch contact based on the random value.

      The sum of the probabilities must be 100.
    additionalProperties: false
    examples:
    - example-description: split based on 2 ranges
      type: .configuration.condition.RandomSplit
      buckets:
      - transitionTo: SomeOtherNode
        name: A
        probability: 30
      - transitionTo: SomeOtherNodeWith70%Probability
        name: B
        probability: 70
  ".configuration.condition.RandomSplit$NamedRange":
    type: object
    properties:
      name:
        type: string
        description: The name of the bucket
      probability:
        type: integer
        description: The probability of the bucket to be selected
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.condition.RandomSplit$NamedRange
    description: A range of probabilities to branch contact based on the random value
    additionalProperties: false
    examples: []
  ".configuration.condition.Time":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.condition.Time
    description: |
      Checks if the time has come.

      This node is not currently supported. Stay tuned.
    additionalProperties: false
  ".configuration.condition.WaitForClick":
    type: object
    properties:
      amount:
        type: integer
        description: The amount of units to delay execution for
      noLinkClickTransition:
        type: string
        description: the name of the node that will be executed if no click received
      nodeWithUrl:
        type: string
        description: the name of the send message node that contains the url
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      units:
        $ref: "#/$defs/DelayUnit"
        description: Units to delay execution for
      url:
        type: string
        description: The url from a send message node that is expected to be clicked
      type:
        const: .configuration.condition.WaitForClick
    description: |
      A workflow node that waits for a provided url to be clicked.
      If no click is received within a specified time, the defined fallback node is executed.
    additionalProperties: false
    examples:
    - example-description: wait for 3 days until the provided url is clicked
      type: .configuration.condition.WaitForClick
      transitionTo: ResumeExecutionNode
      amount: 3
      units: DAY
      noLinkClickTransition: ifNoClickNodeName
      nodeWithUrl: SendMessageNode
      url: https://example.com/click
  ".configuration.condition.WaitForReply":
    type: object
    properties:
      amount:
        type: integer
        description: The amount of units to delay execution for
      noReplyReceivedTransition:
        type: string
        description: the name of the node that will be executed if no reply received
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      units:
        $ref: "#/$defs/DelayUnit"
        description: Units to delay execution for
      type:
        const: .configuration.condition.WaitForReply
    description: |
      Wait for reply after sending a message.

      Can branch based on no matching condition.

      Sets a reply variable based on the reply received.
    additionalProperties: false
    examples:
    - example-description: wait for 3 days until customer texts in text that contains word EXAMPLE ignoring case
      type: .configuration.condition.WaitForReply
      transitionTo: ResumeExecutionNode
      amount: 3
      units: DAY
      noReplyReceivedTransition: ifNoReplyReceivedNodeName
      condition:
        js: |
          input.messageText.toUpperCase().includes('EXAMPLE')
      variable: replyFromCustomer
    allOf:
    - type: object
      properties:
        condition:
          anyOf:
          - $ref: "#/$defs/.condition.And"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Or"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Not"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.JS"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Variable"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Operation"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
        variable:
          type: string
          description: the variable name to use to set the resulting input value to after successful condition evaluation
          pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      description: "Condition to evaluate, and variable to set the result to combination. Used in nodes when both are present."
      additionalProperties: false
  ".configuration.trigger.ExternalWebhook":
    type: object
    properties:
      authKey:
        type: string
        description: Authentication key for the webhook. Must be populated if authType is set
      authType:
        $ref: "#/$defs/WebhookAuthType"
        description: Authentication type for the webhook. Might be empty to use no authentication
      authValue:
        type: string
        description: "Authentication value for the webhook to check against. Must be populated if authType is set. The value will be encrypted and hidden after save. To change the value - update it, otherwise populate with 'hidden' keyword to leave the same."
      jsExtractor:
        type: string
        description: |
          Java Script extractor function that accepts 'body' variable as string that is passed to this webhook and transforms it one of the 2 ways:
          * return a plain phone number value
          * return a map/object with one of the keys as 'phoneNumber' to launch an execution for. All other values will be saved into execution variables and can be reused later in execution
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      webhookId:
        type: string
        description: Webhook ID to trigger for this trigger
        readOnly: true
      type:
        const: .configuration.trigger.ExternalWebhook
    description: |
      External webhook trigger to allow triggering execution for a contact based on the external trigger.

      Having a webhookId of "111-222-333" you can trigger POST request to https://a.eztexting.com/open/workflow/trigger/111-222-333 with the body that will be passed to the jsExtractor as a "body" variable.

      jsExtractor may parse or transform the body and extract phoneNumber at which the trigger will execute. The result of the trigger may be a string, map or object that will be saved into initial variables for the execution.

      Passing a "test" query parameter value as "true" will initiate test execution for that trigger.

      For authentication authKey and authValue should be used. authValue is encoded to be saved and cannot be further read, only rewritten.
    additionalProperties: false
    examples:
    - example-description: |-
        example for a webhook with header authentication that extracts just a phone number from body via parsing a json
        note - webhookId will be provided upon save
      type: .configuration.trigger.ExternalWebhook
      transitionTo: next node name
      webhookId: 111-222-333
      authType: HEADER
      authKey: some-secret-header
      authValue: some-secret-value-to-check-against
      jsExtractor: |
        JSON.parse(body).phoneNumber
    - example-description: |-
        example for a webhook with basic authentication that extracts a phoneNumber and someOtherKey from body via parsing a json, a phoneNumber will not be saved to execution variables, other values will be populated to execution variables
        note - webhookId will be provided upon save
      type: .configuration.trigger.ExternalWebhook
      transitionTo: next node name
      webhookId: 111-222-333
      authType: BASIC
      authKey: username
      authValue: password-will-be-hidden
      jsExtractor: |
        let json = JSON.parse(body);
        ({phoneNumber: JSON.parse(body).phoneNumber, someOtherKey: json.someOtherValue})
  ".configuration.trigger.InboundMessage":
    type: object
    properties:
      numbers:
        description: "trigger fires only if the message was sent to one of these numbers. If empty, applies to all numbers"
        type: array
        items:
          type: string
      restrictions:
        description: restrictions for trigger to restrict when this trigger will apply
        type: array
        items:
          $ref: "#/$defs/Restriction"
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.trigger.InboundMessage
    description: |
      Trigger a workflow on a inbound message from a contact

      Condition is matched against the text. Variable name: input.messageText.

      Detailed examples for restrictions can be found in corresponding type.
    additionalProperties: false
    examples:
    - example-description: |-
        will trigger workflow for a contact which just texted to account number 14243335551 with word HELP in the text ignoring case
        the result of the variables will be saved into inboundTextInput variable for the execution and can be later accessed like: inboundTextInput.messageText
        one restriction added to trigger only on weekends
      type: .configuration.trigger.InboundMessage
      transitionTo: next node
      condition:
        js: |
          input.messageText.toUpperCase().includes('HELP')
      variable: inboundTextInput
      restrictions:
      - enabledFrom: 00:00:00
        enabledTo: 23:59:00
        enabledDays:
        - SATURDAY
        - SUNDAY
        type: WEEKDAY
      numbers:
      - 14243335551
    allOf:
    - type: object
      properties:
        condition:
          anyOf:
          - $ref: "#/$defs/.condition.And"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Or"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Not"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.JS"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Variable"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
          - $ref: "#/$defs/.condition.Operation"
            description: |-
              Condition to evaluate, must result in boolean or to evaluate to true to have string value (case insensitive): 'true', 'on', 'y', 't' or 'yes'.
              The value is usually passed as 'input'. Might contain key values. Check the corresponding containing class info for detailed variables passed to the computation
        variable:
          type: string
          description: the variable name to use to set the resulting input value to after successful condition evaluation
          pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      description: "Condition to evaluate, and variable to set the result to combination. Used in nodes when both are present."
      additionalProperties: false
  ".configuration.trigger.KeywordJoined":
    type: object
    properties:
      keywordIds:
        description: keyword ids to trigger for
        type: array
        items:
          type:
          - string
          - number
      numbers:
        description: "trigger fires only if the message was sent to one of these numbers. If empty, applies to all numbers"
        type: array
        items:
          type: string
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      variable:
        type: string
        description: the variable name to use to set the keyword and number value to
        pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      type:
        const: .configuration.trigger.KeywordJoined
    description: |
      Trigger a workflow when a contact joins a keyword via texting to it and receives auto replies.
    additionalProperties: false
    examples:
    - example-description: |-
        will trigger workflow for a contact which received autoreply for a number 14243335551 keyword with ids: 123, 345
        the variables will be saved into keywordJoinedInput variable for the execution and can be later accessed like: keywordJoinedInput.number or keywordJoinedInput.keyword
      type: .configuration.trigger.KeywordJoined
      transitionTo: next node name
      keywordIds:
      - 123
      - 345
      numbers:
      - 14243335551
      variable: keywordJoinedInput
  ".configuration.trigger.ListJoined":
    type: object
    properties:
      contactSource:
        $ref: "#/$defs/ContactSource"
        description: Contact source to trigger on
      listIds:
        description: Contact list IDs to trigger on
        type: array
        items:
          type:
          - string
          - number
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      variable:
        type: string
        description: the variable name to use to set the contacts source value to
        pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      type:
        const: .configuration.trigger.ListJoined
    description: |
      Trigger a workflow when contact joins a contact list/group, based on the contact source this contact has joined via.
    additionalProperties: false
    examples:
    - example-description: will trigger webhook whenever someone joins contact list 123 via keyword.
      type: .configuration.trigger.ListJoined
      transitionTo: next node
      contactSource: KEYWORD
      listIds:
      - 123
    - example-description: |-
        will trigger webhook whenever someone uploads contacts into 123 list.
        the result of the variables will be saved into listJoinedInput variable for the execution and can be later accessed like: listJoinedInput.contactSource
      type: .configuration.trigger.ListJoined
      transitionTo: next node
      contactSource: UPLOAD
      listIds:
      - 123
      variable: listJoinedInput
  ".configuration.trigger.ListOnDateTime":
    type: object
    properties:
      field:
        type: string
        description: Field to calculate relativity based on
      listIds:
        description: Contact list IDs to trigger for
        type: array
        items:
          type:
          - string
          - number
      relativeAmount:
        type: integer
        description: The number of units to delay before/after trigger launch
      relativeUnits:
        $ref: "#/$defs/DelayUnit"
        description: Units to use in conjunction with amount to calculate the trigger time
      relativityType:
        $ref: "#/$defs/RelativeTriggerType"
        description: Which time direction should a trigger calculate relative to contact field
      scheduledDate:
        examples:
        - 2030-12-31
        description: Date to trigger on. Used for static type
        additionalProperties: false
        type: string
        format: date
      scheduledTime:
        examples:
        - 23:59:59
        description: Time to trigger on. Used for both static and dynamic types
        additionalProperties: false
        type: string
        format: time
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      triggerType:
        $ref: "#/$defs/DateTimeTriggerType"
        description: Trigger type to use when calculating trigger time. Choose static to specify a date and time in the future and dynamic to calculate based on the contact field.
      type:
        const: .configuration.trigger.ListOnDateTime
    description: |
      Trigger a workflow for a contact list/group when a date and time is reached.
    additionalProperties: false
    examples:
    - example-description: will trigger for 123 list on a last day of the 2025 year at 20:00 in account's time zone.
      type: .configuration.trigger.ListOnDateTime
      transitionTo: next node name
      triggerType: STATIC
      scheduledDate: 2025-12-31
      scheduledTime: 20:00:00
      listIds:
      - 123
    - example-description: will trigger execution 1 day before contact has a birthday date time field in list 123
      type: .configuration.trigger.ListOnDateTime
      transitionTo: next node name
      triggerType: DYNAMIC
      listIds:
      - 123
      field: appointment
      relativeAmount: 1
      relativeUnits: DAY
      relativityType: BEFORE
    - example-description: will trigger execution on the date contact has a birthday date field at 13:00 in the account's time zone in list 123
      type: .configuration.trigger.ListOnDateTime
      transitionTo: next node name
      triggerType: DYNAMIC
      scheduledTime: 13:00:00
      listIds:
      - 123
      field: birthday
      relativityType: ON_DATE
  ".configuration.trigger.ShopifyAbandonedCheckout":
    type: object
    properties:
      lookBackMinutes:
        type:
        - string
        - number
        description: Enter the number of minutes you want the system to look back when finding abandoned Shopify shopping carts.
      shopifySite:
        type: string
        description: "Shopify shop name. You can find it in the url For example, if the URL is https://example.myshopify.com/admin, then your shop name is 'example'"
      shopifyToken:
        type: string
        description: Shopify Admin Access Token. Obtain via Settings -> Apps -> Develop apps -> Create an App -> Install app. See detailed description in trigger description.
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      type:
        const: .configuration.trigger.ShopifyAbandonedCheckout
    description: |
      Trigger for Shopify abandoned checkout.

      Monitors the abandoned carts and trigger the execution based on the new values.

      Note: since Shopify doesn't provide a webhook notifications the system is polling for new abandoned checkouts, and they are not triggered immediately.

      To configure:
      You can find your shop name in the URL. For example, if the URL is https://example.myshopify.com/admin, then your shop name is example.
      Set it as a value for 'shopifySite' field in node configuration.

      Admin Token:
          * Login to Shopify account
          * Go to Settings -> Apps -> Develop apps -> Create an App
          * Fill the app name
          * Click on Configure Admin API Scopes and select:
            ** 'read_orders'
            ** 'write_orders'
            ** 'write_customers'
            ** 'read_customers'
            ** 'write_products'
            ** 'read_products'
            ** 'write_draft_orders'
            ** 'read_draft_orders'
          * Click on Install app and copy the Admin Access Token

      'shopifyToken' is encoded on save and can't be further read; only rewritten.

      Available Variables:
          * 'shopifyFirstName': Customer's first name
          * 'shopifyLastName': Customer's last name
          * 'shopifyFirstItemTitle': Title of the first item in cart
          * 'shopifyFirstItemPrice': Price of the first item in cart
          * 'shopifyTotalItemsCount': Total number of items in cart
          * 'shopifyAdditionalItemsCount': Total number of items minus 1
          * 'shopifySmsConsent': Customer's SMS consent status
          * 'shopifyEmailConsent': Customer's email consent status
          * 'shopifyCartToken': Unique token for the abandoned checkout cart
          * 'shopifyAbandonedCheckoutUrl': Direct link to the abandoned checkout cart
    additionalProperties: false
    examples: []
    allOf:
    - type: object
      properties:
        accepted:
          type: boolean
          description: Indicates whether the user has accepted the agreement.
        acceptedAt:
          type: string
          format: date-time
          description: Timestamp when the agreement was accepted.
      description: |
        User agreement configuration for abandoned checkout processing.

        This agreement must be accepted before the system can process abandoned checkouts.
        The acceptance is tracked with a timestamp for audit purposes.

        Once accepted, the agreement cannot be modified through API requests to maintain
        data integrity and compliance requirements.
      additionalProperties: false
  ".configuration.trigger.SignupFormCompleted":
    type: object
    properties:
      transitionTo:
        type: string
        description: The name of the node to transition to after executing current configuration
      variable:
        type: string
        description: the variable name to use to set the signup form name value to
        pattern: "^([a-zA-Z][-a-zA-Z0-9\\.]*)$"
      widgetIds:
        description: signup form ids to trigger for
        type: array
        items:
          type: string
      type:
        const: .configuration.trigger.SignupFormCompleted
    description: |
      Triggers for when a contact completes a signup form
    additionalProperties: false
    examples:
    - example-description: |-
        will trigger workflow for a contact which just completed a sign up form 123
        the variables will be saved into signupFormInput variable for the execution and can be later accessed like: signupFormInput.signupForm
      type: .configuration.trigger.SignupFormCompleted
      transitionTo: next node name
      widgetIds:
      - 123
      variable: signupFormInput
  ContactSource:
    type: string
    enum:
    - UNKNOWN
    - WEBINTERFACE
    - UPLOAD
    - WEBWIDGET
    - API
    - WORKFLOW
    - KEYWORD
    - INTEGRATION_MAILCHIMP
    - INTEGRATION_HIGHRISE
    - INTEGRATION_AWEBER
    - INTEGRATION_CONSTANTCONTACT
    - INTEGRATION_EVENTBRITE
    - INTEGRATION_ICONTACT
    - INTEGRATION_SALESFORCE
    - INTEGRATION_INFUSION
    - INCOMING
    - INTEGRATION_ZAPIER
    - INTEGRATION_SQUARESPACE
    - INTEGRATION_HUBSPOT
    - INTEGRATION_NATION_BUILDER
    - INTEGRATION_ZOHO
    - INTEGRATION_NETSUITE
    - INTEGRATION_SALES_GENIE
    - OUTBOUND
    - INTEGRATION_SHOPIFY
  DateTimeTriggerType:
    type: string
    enum:
    - STATIC
    - DYNAMIC
  DayOfWeek:
    type: string
    enum:
    - MONDAY
    - TUESDAY
    - WEDNESDAY
    - THURSDAY
    - FRIDAY
    - SATURDAY
    - SUNDAY
  DelayUnit:
    type: string
    enum:
    - MINUTE
    - HOUR
    - DAY
  FieldExpression:
    type: object
    properties:
      expression:
        type: string
        description: The result of JS expression is assigned to a field value.
      fieldName:
        type: string
        description: "Field name. Can be name of a predefined fields like firstName or custom1, or a name of a custom field"
    description: |
      An expression to update contact field, can be JS compatible expression including variables and string literals.
    additionalProperties: false
    examples:
    - example-description: updates a contact's field value
      fieldName: firstName
      expression: customer
  JsonNode:
    type: object
    additionalProperties: false
  Map(String,String):
    type: object
    additionalProperties: false
  MessageType:
    type: string
    enum:
    - SMS
    - MMS
    - DID_SMS
    - RCS_RBM
    - RCS_ABC
  Method:
    type: string
    enum:
    - GET
    - HEAD
    - POST
    - PUT
    - DELETE
    - CONNECT
    - TRACE
    - OPTIONS
    - PATCH
  Node(Configuration):
    type: object
    properties:
      config:
        anyOf:
        - $ref: "#/$defs/.configuration.action.Delay"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.DeleteContact"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.HttpRequest"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.OptOut"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.SendMessage"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.SetVariable"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.action.UpdateContact"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.InList"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.OptOut"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.RandomSplit"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.Time"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.If"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.WaitForReply"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.condition.WaitForClick"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.ListJoined"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.KeywordJoined"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.ListOnDateTime"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.InboundMessage"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.SignupFormCompleted"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.ExternalWebhook"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
        - $ref: "#/$defs/.configuration.trigger.ShopifyAbandonedCheckout"
          description: "the configuration of the node. May be any of the supported configurations (triggers, conditions, actions)"
      created:
        type: string
        format: date-time
        description: node creation date
        readOnly: true
      frontConfig:
        $ref: "#/$defs/JsonNode"
        description: technical UI configuration for the node. stores the placements on the UI and can safely be ignored/deleted
      id:
        type:
        - string
        - number
        description: the unique identifier of the node
      modified:
        type: string
        format: date-time
        description: node last modification date
        readOnly: true
      name:
        type: string
        description: the name of the node. must be unique within a workflow
        minLength: 1
      action.Delay:
        description: |-
          the configuration of the node of type: .configuration.action.Delay. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.Delay"
      action.DeleteContact:
        description: |-
          the configuration of the node of type: .configuration.action.DeleteContact. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.DeleteContact"
      action.HttpRequest:
        description: |-
          the configuration of the node of type: .configuration.action.HttpRequest. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.HttpRequest"
      action.OptOut:
        description: |-
          the configuration of the node of type: .configuration.action.OptOut. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.OptOut"
      action.SendMessage:
        description: |-
          the configuration of the node of type: .configuration.action.SendMessage. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.SendMessage"
      action.SetVariable:
        description: |-
          the configuration of the node of type: .configuration.action.SetVariable. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.SetVariable"
      action.UpdateContact:
        description: |-
          the configuration of the node of type: .configuration.action.UpdateContact. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.action.UpdateContact"
      condition.InList:
        description: |-
          the configuration of the node of type: .configuration.condition.InList. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.InList"
      condition.OptOut:
        description: |-
          the configuration of the node of type: .configuration.condition.OptOut. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.OptOut"
      condition.RandomSplit:
        description: |-
          the configuration of the node of type: .configuration.condition.RandomSplit. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.RandomSplit"
      condition.Time:
        description: |-
          the configuration of the node of type: .configuration.condition.Time. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.Time"
      condition.If:
        description: |-
          the configuration of the node of type: .configuration.condition.If. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.If"
      condition.WaitForReply:
        description: |-
          the configuration of the node of type: .configuration.condition.WaitForReply. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.WaitForReply"
      condition.WaitForClick:
        description: |-
          the configuration of the node of type: .configuration.condition.WaitForClick. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.condition.WaitForClick"
      trigger.ListJoined:
        description: |-
          the configuration of the node of type: .configuration.trigger.ListJoined. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.ListJoined"
      trigger.KeywordJoined:
        description: |-
          the configuration of the node of type: .configuration.trigger.KeywordJoined. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.KeywordJoined"
      trigger.ListOnDateTime:
        description: |-
          the configuration of the node of type: .configuration.trigger.ListOnDateTime. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.ListOnDateTime"
      trigger.InboundMessage:
        description: |-
          the configuration of the node of type: .configuration.trigger.InboundMessage. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.InboundMessage"
      trigger.SignupFormCompleted:
        description: |-
          the configuration of the node of type: .configuration.trigger.SignupFormCompleted. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.SignupFormCompleted"
      trigger.ExternalWebhook:
        description: |-
          the configuration of the node of type: .configuration.trigger.ExternalWebhook. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.ExternalWebhook"
      trigger.ShopifyAbandonedCheckout:
        description: |-
          the configuration of the node of type: .configuration.trigger.ShopifyAbandonedCheckout. This can be used as alternative to 'config' property, for a content assist and strong typing validation.
          One can omit the child type if using this property name.
        $ref: "#/$defs/.configuration.trigger.ShopifyAbandonedCheckout"
    required:
    - name
    description: |
      A named node holding some configuration.
      Node is referenced by its name.
      Node names must be unique within a workflow.
    additionalProperties: false
    examples:
    - example-description: shows example of config configuration (possible)
      id: 123
      name: Some mnemonic and unique node name
      created: 2030-01-31T15:00:00Z
      modified: 2030-01-31T15:00:00Z
      config:
        type: .configuration.action.SendMessage
        transitionTo: SomewhereNext
        subject: Your Company Name
        messageType: MMS
        message: |
          Message to send
        containsSuspiciousWords: false
      frontConfig: something not important for code editing
    - example-description: shows example of typed configuration (also possible)
      id: 123
      name: Some mnemonic and unique node name
      created: 2030-01-31T15:00:00Z
      modified: 2030-01-31T15:00:00Z
      config:
        type: .configuration.action.SendMessage
        transitionTo: SomewhereNext
        subject: Your Company Name
        messageType: SMS
        message: |
          Message to send
        containsSuspiciousWords: false
    oneOf:
    - required:
      - config
    - required:
      - action.Delay
    - required:
      - action.DeleteContact
    - required:
      - action.HttpRequest
    - required:
      - action.OptOut
    - required:
      - action.SendMessage
    - required:
      - action.SetVariable
    - required:
      - action.UpdateContact
    - required:
      - condition.InList
    - required:
      - condition.OptOut
    - required:
      - condition.RandomSplit
    - required:
      - condition.Time
    - required:
      - condition.If
    - required:
      - condition.WaitForReply
    - required:
      - condition.WaitForClick
    - required:
      - trigger.ListJoined
    - required:
      - trigger.KeywordJoined
    - required:
      - trigger.ListOnDateTime
    - required:
      - trigger.InboundMessage
    - required:
      - trigger.SignupFormCompleted
    - required:
      - trigger.ExternalWebhook
    - required:
      - trigger.ShopifyAbandonedCheckout
  OperationDataType:
    type: string
    enum:
    - text
    - number
    - date
  OperationType:
    type: string
    enum:
    - eq
    - ne
    - contains
    - notContains
    - startsWith
    - endsWith
    - gt
    - lt
    - exist
    - notExist
  RelativeTriggerType:
    type: string
    enum:
    - BEFORE
    - AFTER
    - ON_DATE
  Restriction:
    type: object
    properties:
      enabledDays:
        description: Enabled only on a specified days
        type: array
        items:
          $ref: "#/$defs/DayOfWeek"
      enabledFrom:
        examples:
        - 23:59:59
        description: Restrict to be enabled only after specified time. If a from time specified after to time - inner time frame will be excluded
        additionalProperties: false
        type: string
        format: time
      enabledTo:
        examples:
        - 23:59:59
        description: Restrict to be enabled only before specified time
        additionalProperties: false
        type: string
        format: time
      fromDate:
        examples:
        - 2030-12-31
        description: Restrict to run from a specific date
        additionalProperties: false
        type: string
        format: date
      toDate:
        examples:
        - 2030-12-31
        description: Restrict to run until a specific date
        additionalProperties: false
        type: string
        format: date
      type:
        $ref: "#/$defs/RestrictionType"
        description: Type of restriction
    description: |
      Restriction for an inbound message to configure time constraints at which a trigger should start.
    additionalProperties: false
    examples:
    - example-description: restrict to trigger between 10:00 and 18:00 and from 2025-01-01 to 2025-02-28
      enabledFrom: 10:00:00
      enabledTo: 18:00:00
      fromDate: 2025-01-01
      toDate: 2025-02-28
      type: DATE
    - example-description: restrict to trigger on weekends
      enabledFrom: 00:00:00
      enabledTo: 23:59:00
      enabledDays:
      - SATURDAY
      - SUNDAY
      type: WEEKDAY
    - example-description: restrict to trigger on weekdays from 00:00 to 9:00 and from 18:00 to 24:00
      enabledFrom: 18:00:00
      enabledTo: 09:00:00
      enabledDays:
      - MONDAY
      - TUESDAY
      - WEDNESDAY
      - THURSDAY
      - FRIDAY
      type: WEEKDAY
  RestrictionType:
    type: string
    enum:
    - DATE
    - WEEKDAY
  Transition:
    type: object
    properties:
      condition:
        anyOf:
        - $ref: "#/$defs/.condition.And"
          description: a condition to be evaluated
        - $ref: "#/$defs/.condition.Or"
          description: a condition to be evaluated
        - $ref: "#/$defs/.condition.Not"
          description: a condition to be evaluated
        - $ref: "#/$defs/.condition.JS"
          description: a condition to be evaluated
        - $ref: "#/$defs/.condition.Variable"
          description: a condition to be evaluated
        - $ref: "#/$defs/.condition.Operation"
          description: a condition to be evaluated
      name:
        type: string
        description: a branch name
      transitionTo:
        type: string
        description: the name of the node that will be executed if condition evaluates to true
    description: |
      A single branch of If node.
      If condition of on one of the transitions evaluates to true then execution proceeds to transitionTo node.
    additionalProperties: false
    examples:
    - example-description: based on the previously set variable (or contact custom field) we can branch the workflow. In this use case we're branching vip clients to specific scenario
      name: Vip Branch
      condition:
        js: |
          contact.vipClient
      transitionTo: NextTrueNode
    - example-description: "branching based on the date, we'll make sure customers will go other branch after some date"
      name: 2030
      condition:
        js: |
          new Date().getYear() > 2030
      transitionTo: After 2030 Branch
    - example-description: branching based on multiple variables
      name: 2030
      condition:
        and:
        - or:
          - js: |
              new Date().getYear() > 2030
          - op: eq
            value: value
            variable: variableName
        - js: |
            contact.vipClient
      transitionTo: After 2030 Branch
  UpdateContactType:
    type: string
    enum:
    - ADD_TO_GROUPS
    - REMOVE_FROM_GROUPS
    - UPDATE_FIELD
  WebhookAuthType:
    type: string
    enum:
    - BASIC
    - HEADER
  WorkflowStatus:
    type: string
    enum:
    - PUBLISHED
    - UNPUBLISHED
    - PAUSED
    - BLOCKED_SUSPICIOUS
    - APPROVED
    - INSUFFICIENT_FUNDS
    - PAUSED_API_FAILURES
    - ARCHIVE
type: object
properties:
  cooldownAmount:
    type: integer
    description: "specifies the amount of time after which the contact can re-enter the workflow. If the time didn't pass, then the contact will not enter to the workflow."
    exclusiveMinimum: 0
  cooldownUnit:
    $ref: "#/$defs/DelayUnit"
    description: units in which cooldown amount will be calculated
  created:
    type: string
    format: date-time
    description: date when the workflow was created
    readOnly: true
  description:
    type: string
    maxLength: 200
  id:
    type:
    - string
    - number
    description: the unique identifier of the workflow
    readOnly: true
  lastStructureModified:
    type: string
    format: date-time
    description: indicates when the workflow structure was last modified
    readOnly: true
  modified:
    type: string
    format: date-time
    description: date when the workflow was last modified
    readOnly: true
  name:
    type: string
    minLength: 1
    maxLength: 200
  nodes:
    description: the list of the nodes for this workflow with references between them
    type: array
    items:
      $ref: "#/$defs/Node(Configuration)"
  runOnlyOnce:
    type: boolean
    description: a setting to indicate whether a contact may enter only once into this workflow
  status:
    $ref: "#/$defs/WorkflowStatus"
    description: the status of the workflow
  timeZone:
    type: string
    description: time zone for a workflow. leave empty to populate time zone from account
required:
- name
- status
description: |
  # Workflows

  A main entrypoint for the workflow engine to execute a sequence of nodes.

  ## Description

  Workflow is a sequence of the actions that are executed one by one to achieve specific logic that is leading to algorithm evaluation in EzTexting.

  ## Workflow nodes
  ##
  Node is an entity that contains configuration of the action that will be executed during the workflow evaluation.

  There are 3 types of nodes:
  1. triggers: those having types that contain '.trigger.'. Triggers are intended to be a starting point of a workflow and can trigger execution for one or multiple contacts. For example when a contact joins a contact list (or someone adds it to the list) an execution for that contact is triggered.
  2.  actions: those having types that contain '.action.'. Actions are intended to perform some action during the workflow execution.
    Example action would be a http request to third party service that is transmitting some data from the EzTexting system, like contact information.
  3.  conditions: those having types that contain '.configuration.'. Conditions are intended to evaluate condition of the execution and branch the execution based on that.
    Example condition is there 'wait for link click' condition that is branching based on the fact that contact clicked or not clicked the link.

  By combining all three types of nodes one can configure algorithm through which contact will be provided through a steps to achieve desired result, like reminding of a birthday for a contact,
  gathering info into contact, making polls etc.

  ## Workflow execution

  A workflow execution is an invocation of the workflow for a contact or a phone number that is transitioning through the nodes.
  A workflow will execute instances/executions if one (or multiple) is triggered via one of the Trigger nodes, resuming execution by transitioning through the tree of the nodes.
  When three reversal is finished, and there is no next nodes to go to a contact will exit the workflow with the status of DONE.
  One configure workflow to accept the same contact multiple times or to accept it after some period of time which is called cool down period.

  ## Variables

  An important part of the workflow execution is a variables that can persist information between nodes and execution invocations.
  They can be in form of the key values, including nested objects/maps. Variables can be reused in a JavaScript evaluations:
      1. one can set a variable to later reuse by SetVariable action
      2. JavaScript code can reference variable same way as a JavaScript is accessing local/global variables as per JavaScript language specification
      3. there are places where variable substitution is in place and can substitute values by the variable keys. Places like HTTP request url, JSON body in http call, message in send message node and other.
        For example, 'send message' node can have message substituted both variables and replacements already known from a Group message composing dialog.

  Below is the example JavaScript that access contact variables and evaluates based on the logic and returns an object as a result, that may be saved to a variable (e.g. in ExternalWebhook trigger):
  ```
      let greeting = 'Hello, ' + (contact.sex == 'M' ? 'Sir' : 'Madam') + contact.lastName';
      let sir = greeting.toUpperCase().includes('SIR');
      let blankLastName = contact.lastName.trim() === "";
      ({isSir: sir, blankLastName: blankLastName, greetVia: greeting})
  ```

  Here is another example that evaluates to true based on the input variables. Assuming input has an object with 2 fields: messageText and requestBody (that also has json with same messageText):
  ```
      JSON.parse(requestBody).messageText === messageText
  ```
additionalProperties: false

Workflows are sequences of automated steps that respond to triggers (like receiving a keyword, inbound SMS, or Shopify abandoned cart), perform actions (like sending a message, making an HTTP request, updating a contact), and check conditions (like waiting for replies, splitting traffic randomly, or evaluating variables).

Key Concepts:

  1. Triggers (.configuration.trigger.*) – Define what starts the workflow.
    Examples:

    • KeywordJoined: When someone texts a keyword.

    • InboundMessage: When a customer replies.

    • ExternalWebhook: When a webhook call is received.

    • ShopifyAbandonedCheckout: When a cart is abandoned.

  2. Actions (.configuration.action.*) – Steps that “do something.”
    Examples:

    • SendMessage: Send an SMS/MMS.

    • HttpRequest: Call an external API.

    • UpdateContact: Change a contact’s group or custom field.

    • Delay: Wait for a certain time before continuing.

  3. Conditions (.configuration.condition.*) – Logic checks and branching.
    Examples:

    • If: Branch flow based on JavaScript or variable conditions.

    • WaitForReply: Pause until a customer replies.

    • WaitForClick: Pause until a link is clicked.

    • RandomSplit: Send contacts down different branches by probability.

  • Nodes:
    Each workflow is made of nodes, and each node has a name and a config that describes whether it’s a trigger, action, or condition. Nodes connect by transitionTo, which points to the next step.

  • Workflow Properties:

    • name, description, status (Published, Paused, etc.)

    • cooldown (how often a contact can re-enter)

    • timeZone

    • nodes (the actual steps of the workflow).

Join the 230,000+ Who Have Used EZ Texting to Connect with Their Audiences.