Building Connector Actions

We provide our SaaS customers an easy way to manage their own connectors and its actions and endpoints.

Introduction

To create a new Connector Action you need to understand the basics of API calls and the corresponding terms we use in the Connector Action creation/edit dialog:

All Actions are created per Connector and you can add them on the Connector settings (you might need to request access by contacting us) - Actions:

A new page will open with all Actions for this Connector, where you can create new ones or edit existing ones:

Create/Edit rights for Connector Actions are given on a per Connector basis, so you might be able to see some Connector Actions, but cannot edit them.

Fields

As shown above, there are quite a lot of different fields which are part of each Action:

  • ID: The UUID of the Action, this is needed if you want to change the Action via API (read-only)

  • Connector: The Connector the Action belongs to (read-only)

  • Action Name: Name of the Action in snake_case, it will be shown in Title Case in the Flow Builder and _ will be replaced by spaces

    • This is usually equal to the endpoint name in the API documentation

    • However, we recommend starting every Action name with the method and indicating with plural forms, whether the action is about one or multiple records, e.g. get_action (= one action) and get_actions (= multiple actions, often also called list_... in API documentations)

  • Order Rank: The order in which the Action will be shown in the Flow Builder

  • Status: Only Actions with status active are visible to non-admin users

  • Short Description: Description of the Action that will be shown in the tooltip in the Flow Builder. This is

  • Tag: Tag the Action should be grouped in the Flow Builder

  • Internal Docs: Link to Locoia documentation, which will be shown in the Flow Builder

  • External Docs: Link to external API documentation, which will be shown in the Flow Builder

  • Method: This can only be left empty for 'special' Actions such as webhook trigger actions

  • Endpoint: This will be appended to the base domain of the Connector

    • When starting the endpoint with /, it will overwrite anything that comes after the first / in the base domain. This is often needed if a few Actions are only available in an older API version than the one specified in the base domain

    • When starting the endpoint with https://, the entire base domain will be overwritten and the endpoint will be used instead. This is needed for APIs where a few Actions have completely different base domains than all other Actions of the same Connector

  • UI Form Schema: JSON which will render the input form that is visible in the Flow Builder. More details below

  • Request Body Template: Jinja which will render the request body. More details below

  • Request Header Template: Jinja will render the request header, which will be used in addition to the Header configured in the Connector. More details below

  • Reporting Flow: Flow used for retrieving data for this Action in a Data Source

  • Pre Save Flow: Flow which creates a webhook (for webhook trigger actions only)

  • On Delete Flow: Flow which deletes a webhook (for webhook trigger actions only)

  • Supports automatic pagination: Whether the action supports automatic pagination. Automatic pagination needs to be configured on the Connector itself in order to work

UI Form Schema

The UI Form Schema

Below is an extensive list of form schema variations:

{
  "ui_form_schema": {
    "classicinput": {
      "required": true,
      "title": "input",
      "type": "text"
    },
    "date": {
      "title": "date",
      "type": "date"
    },
    "daterange": {
      "title": "date A and B",
      "type": "daterange"
    },
    "datetime": {
      "required": true,
      "title": "date and time",
      "type": "datetime"
    },
    "email": {
      "placeholder": "E-mail zum bestätigen",
      "title": "Email",
      "type": "email"
    },
    "multiselect": {
      "default": [
        "normal",
        "low"
      ],
      "enum": [
        "urgent",
        "high",
        "normal",
        "low"
      ],
      "allowCreate": true,
      "multiple": true,
      "title": "multi select",
      "type": "select"
    },
    "number": {
      "default": 2,
      "max": 3,
      "min": -1,
      "step": 0.25,
      "title": "Zahl zwischen -1 und 3",
      "type": "number"
    },
    "password": {
      "title": "password",
      "type": "password"
    },
    "singleselect": {
      "default": "problem",
      "enum": [
        "problem",
        "incident",
        "question",
        "task"
      ],
      "title": "single selct",
      "type": "select"
    },
    "switch": {
      "default": true,
      "title": "Aus/An",
      "type": "switch"
    },
    "textarea": {
      "info": "Type some text",
      "maxLength": 20,
      "minLength": 10,
      "placeholder": "Type...",
      "required": true,
      "rows": 3,
      "title": "textarea",
      "type": "text"
    }
  }
}

To allow a user to add manually their own custom options in a select dropdown, add the below to:

"type": "select",
"allowCreate": true

Multiple select (enum)

Screenshot of how it looks to the user:

UI form schema example:

{
  "include": {
    "title": "Details to include",
    "type": "select",
    "multiple": true,
    "enum": [
      "owner",
      "creator",
      "updater",
      "source",
      "contacts",
      "sales_account",
      "deal_stage",
      "deal_type",
      "deal_reason",
      "campaign",
      "deal_payment_status",
      "deal_product",
      "currency",
      "probability",
      "created_at",
      "updated_at"
    ]
  }
}

Request body usage:

{
    "include": {{ include | jsonify }}
}

Endpoint (query parameter) usage of multi select:

Example of a multi select in the URL parameters to get a list as a result: [ "owner", "contacts",... ]

{% if include %}
  &include={{ include | replace("[", "") | replace("]", "") | replace("'", "") | replace(" ", "") }}
{% endif %}

Local language translations

A translation can be added to the following fields:

  • title

  • placeholder

  • info

  • regexErrorMessage

An array with en and de keys should be added to a field to define the translations in English and German correspondingly e.g.:

 {
  "classicinput": {
      "required": true,
      "title": {
        "en": "Title",
        "de": "Titel"
	},
      "type": "text"
    }
  }

This is especially useful for the Form Helper, where end users might prefer one over another language.

Action endpoints and building their query strings dynamically

In order to build query strings dynamically (i.e. not having to take care of when to use ? vs &) always use & and our backend will dynamically take care of placing the ? correctly by replacing the first occurrence of & with ? Note: This is only being done if the query string does not include a ?

Custom Fields

In order to allow custom fields where the type may not be known to send data in the right format, the following formats have to be used.

Request Body

I.e. booleans and numbers without quotation marks the following line has to be inserted, instead of "{{ item.key }}": "{{ item.value }}" , when configuring the connector action request body:

{% if custom_fields is defined and custom_fields | length > 0 %}
  {% set comma_set = namespace(first_comma_set=False) %}
  "custom_fields": { {# This field/name depends on how the custom fields are supposed to be sent to the API #}
    {% for item in custom_fields %}
      {% if probe(item, 'value') %}
        {% if comma_set.first_comma_set %},{% else %}{% set comma_set.first_comma_set = True %}{% endif %}
        "{{ item.key }}": {% if item.type == 'number' %}{{ item.value }}{% elif item.type == 'switch' %}{{ item.value | lower }}{% else %}"{{ item.value }}"{% endif %}
      {% endif %}
    {% endfor %}
  }
{% endif %}

Endpoint

Custom fields can also be used in the endpoint:

{% if custom_fields is defined %}{% for item in custom_fields %}&{{ item.key }}={{ item.value }}{% endfor %}{% endif %}

The most known use-case for this is for APIs, such as Zendesk or Salesforce, that are popular for using custom fields, added by each user individually.

Code Highlighting for SQL, htmlmixed, jinja2, javascript, python

Add code highlighting by making the type `code` and adding the mode type to one of these five sql, htmlmixed, jinja2, javascript, python (letters all lowercase). Further syntax highlighting can be added upon request as per: Code Highlighting

{
  "myField": {
    "type": "code",
    "mode": "sql",
    "title": "My Title"
  }
}

Nested Form Schema

Example image

Example code

{
  "clickEvent": {
    "title": "Click Event",
    "type": "nested_object",
    "children": {
      "shouldReactOnClick": {
        "title": "Click on/off",
        "type": "switch",
        "info": "Determine if clicking on a value on the chart should open a link.",
        "default": false
      },
      "urlTemplate": {
        "title": "URL template",
        "info": "Base URL with placeholders (use the SQL columns with doubly curly braces).",
        "type": "text",
        "placeholder": "https://www.google.com/search?q={{category}}"
      },
      "test": {
        "title": "Test",
        "info": "test",
        "type": "nested_object",
        "children": {
          "testChild": {
            "title": "testChild",
            "type": "text"
          },
          "testChild2": {
            "title": "testChild2",
            "type": "text"
          },
          "test": {
            "title": "Test",
            "info": "test",
            "type": "nested_object",
            "children": {
              "testChild": {
                "title": "testChild",
                "type": "text"
              },
              "testChild2": {
                "title": "testChild2",
                "type": "text"
              },
              "test": {
                "title": "Test",
                "info": "test",
                "type": "nested_object",
                "children": {
                  "testChild": {
                    "title": "testChild",
                    "type": "text"
                  },
                  "testChild2": {
                    "title": "testChild2",
                    "type": "text"
                  },
                  "test": {
                    "title": "Test",
                    "info": "test",
                    "type": "nested_object",
                    "children": {
                      "testChild": {
                        "title": "testChild",
                        "type": "text"
                      },
                      "testChild2": {
                        "title": "testChild2",
                        "type": "text"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Expanding List

In certain situations, you may want to expand the list on your Embed.

Example image

Example code

In order for a Form to work, there are two fundamentals.

  • It's necessary to provide "type": "expanding_list".

  • It's necessary to include “nested_schema”

{
  "User details": {
    "title": "Adding details",
    "type": "expanding_list",
    "nested_schema": {
      "example": {
        "title": "Customer details",
        "type": "text",
        "default": "default value 1"
      }
    }
  }
}

Sending emails

Often email providers expect content to be encoded using based64. Please use the Jinja filter base64_encode (or base64_decode) for this like this:

{{ myEmailContent | base64_encode }}

Regular Expression (RegEx) Validation

To validate the user input for the fields, you can make use of RegEx in order to be fully flexible with the validation. To use it, these two fields need to be added to the form schema:

  • pattern - The RegEx pattern (Note: The backslash (\) which is commonly used in RegEx patterns needs to be escaped, so instead of \ two backslashes need to be used: \\)

  • regexErrorMessage - The error message that should be displayed when the input doesn't match the pattern

For example, you might have a field for the Server URL, which validates the user input:

"server_url": {
  "title": "FTP Server URL",
  "type": "text",
  "required": true,
  "placeholder": "ftp://my.server.com:22",
  "info": "Start your path with the protocol (ftp/ftps/sftp), followed by the domain of your server and followed by the port.",
  "pattern": "/^s{0,1}ftps{0,1}:\\/\\/[\\w-_./]+:\\d+$/",
  "regexErrorMessage": "Required formats: ftps://server-domain.com:22 or starting with sftp:// ftp://"
}

For a typical Connector, the pattern often looks similar to that of the Freshsales connector.

"pattern": "/^https:\\/\\/[\\w-_]+\\.freshsales\\.io\\/api\\/$/"

In order to validate Jinja reference or url input this pattern can be used:

"pattern": "/^({{|{%http).+$/"

If the entire input should match the pattern you need to include /^your_pattern$/.

^ is the start of the line and $ is the end of the line.

You can easily setup and test your RegEx patterns in tools like RegExr.

UUID mappings in select drop-downs

E.g. LexOffice has UUIDs for categories like:

Warenverkäufe	8f8664a8-fd86-11e1-a21f-0800200c9a66

This can be solved with the following in the request body template:

{% set categoryMapping = {"Warenverkäufe":"8f8664a8-fd86-11e1-a21f-0800200c9a66", .. }

{
    ...
    "categoryId": "{{ categoryMapping[categoryId] }}"
    ...
}

Now the UI Form Schema can just have a list (select) with values like Warenverkäufe .

Available variables and Jinja functions

In the Actions, almost all Jinja variables and functions that are available in Flows are available in the Action's endpoint, request body, and request header as well, except for these:

  • date date_de

  • date_utc

  • date_us

  • date_de_7

  • date_utc_7

  • date_us_7

  • date_de_30

  • date_utc_30

  • date_us_30

  • date_de_180

  • date_utc_180

  • date_us_180

  • datetime

  • time

  • unix_timestamp

  • last_execution

  • last_execution_succeeded

  • last_execution_start_date

  • last_execution_end_date

  • last_execution_success

  • last_execution_success_start_date

  • last_execution_success_end_date

  • flow_run_triggered_by

These variables and functions are only available in Actions:

  • unix_time() - Same as unix_timestamp in Flows

Ignore http errors - (Deprecated)

This functionality is deprecated, instead custom error handling should be used (no special Connector Action setup needed)

The following field "ignore_http_errors" can be included on any endpoint in order to exclude http errors. Like this

{
  "ignore_http_errors": {
    "type": "switch",
    "title": "Ignore http Errors"
  }
}

Last updated