# How-to guides - Static Webhook Trigger

A static webhook trigger is one that requires manual registration. This usually involves a user creating a webhook subscription in the application's UI with a provided webhook URL.

WARNING

When you define a static webhook trigger for your connector, take note that you will not be able to define a dynamic webhook trigger. Only one type of webhook trigger is allowed in a single connector. You may have both a polling trigger and one type of webhook trigger in your connector.

# Sample connector - Greenhouse

{
  title: 'My Greenhouse connector',

  # More connector code here
  webhook_keys: lambda do |params, headers, payload|
    "#{params['org_id']}@#{payload['action']}"
  end,

  triggers: {
    new_event: {
      title: 'New Candidate Event',

      subtitle: "Triggers when a Candidate event is received " \
      "from Greenhouse",

      description: lambda do |input, picklist_label|
        "New <span class='provider'>candidate event</span> " \
        "in <span class='provider'>Greenhouse</span>"
      end,

      help: lambda do |input, picklist_label, connection, webhook_base_url|
        next unless webhook_base_url.present?
        <<~HTML
        Creates an job when an event is received from Greenhouse. To set this webhook up,
        you will need to register the webhook below in Greenhouse under "settings" => "webhooks" => "new". <br>
        <b>Webhook endpoint URL</b>
        <b class="tips__highlight">#{webhook_base_url}?org_id=#{connection['org_id']}</b>
        HTML
      end,

      input_fields: lambda do |object_definitions|
        [
          {
            name: 'event_type',
            label: 'Event',
            control_type: 'select',
            pick_list: 'events',
            optional: false,
            hint: 'Select specific event.'
          }
        ]
      end,

      webhook_key: lambda do |connection, input|
        "#{connection['org_id']}@#{input['event_type']}"
      end,

      webhook_notification: lambda do |input, payload, extended_input_schema, extended_output_schema, headers, params|
        payload.dig('payload', 'candidate')
      end,

      dedup: lambda do |record|
        record['id']
      end,

      output_fields: lambda do |object_definitions|
        [
          {
            name: 'id'
          },
          {
            name: 'rejected_at'
          },
          {
            name: 'prospect'
          },
          {
            name: 'prospect_detail',
            type: 'object',
            properties: [
              {
                name: 'prospect_pool',
                type: 'object',
                properties: [
                  {
                    name: 'id',
                    type: 'integer',
                    control_type: 'integer'
                  },
                  {
                    name: 'name'
                  }
                ]
              },
            ]
          }
         ]
        end,

        sample_output: lambda do |connection, input|
          if input['event_type'] == "candidate_stage_change"
            get("v1/applications?per_page=1")&.dig(0) || {}
          else
            get("v1/#{input['object']&.pluralize}?per_page=1")&.dig(0) || {}
          end
        end
    }
  },

  pick_lists: {
    events: lambda do |connection|
      [
        ["Candidate Updated", "update_candidate"],
        ["Candidate Stage Changed", "candidate_stage_change"]
      ]
    end
  }
  # More connector code here
}

# Steps:

# Step 1 - Set up the webhook_keys attribute and retrieve your connector static webhook URL

webhook_keys is a top level key (connector-wide definition). This lambda function is called for each webhook your connector receives via its assigned webhook URL and allows you to define a routing key for each incoming webhook. For example:

  • With this definition
    webhook_keys: lambda do |params, headers, payload|
      "#{params['org_id']}@#{payload['action']}"
    end,
  • and an incoming webhook with the following shortened body from Greenhouse
URL: https://www.workato.com/user/123/connector/abc?org_id=555
{
  "action": "candidate_stage_change",
  "payload": {
    "application": {
      "id": 265277,
      "rejected_at": null,
      "prospect": false,
      "status": "active",
      "applied_at": "2013-03-22T00:00:00Z",
      "last_activity_at": "2015-02-09T16:38:36Z",
      "url": "https://app.greenhouse.io/people/265772?application_id=265277",
      "source": {
        "id": 31,
        "name": "Agency"
      },
  # More information here    
}

The resultant webhook_keys output for this webhook payload should be 555@candidate_stage_change. This key is used to route these events to the proper triggers as you may have multiple static webhook triggers.

To retrieve your connector's static webhook URL, head to the debugger in your connector SDK console. You will find the static webhook URL there.

Static webhook URL Static webhook URL in debugger console

# Step 2 - Trigger title, subtitle and description

The first step to making a good trigger is to properly communicate what the trigger does and to provide additional help to users. To do so, Workato allows you to define the title, description, and provide hints for an action. Quite simply, the title is the title of an action and the subtitle provides further details of the action. The description of the action then contains specifications and explanation on what the action accomplishes and in the context of the application it connects to.

To know more about this step, take a look at our SDK reference

# Step 3 - Define your help with your static webhook url

Another important part of building a static webhook trigger is displaying the webhook url prominently so users can take this and register it. To do this, you can utilize the help lambda that allows you to display your connector's static webhook url. Additionally, you may add query parameters in the displayed webhook URL which can be utilized in conjunction with webhook_key and webhook_keys to route events to specific recipes.

      help: lambda do |input, picklist_label, connection, webhook_base_url|
        next unless webhook_base_url.present?
        <<~HTML
        Creates an job when an event is received from Greenhouse. To set this webhook up,
        you will need to register the webhook below in Greenhouse under "settings" => "webhooks" => "new". <br>
        <b>Webhook endpoint URL</b>
        <b class="tips__highlight">#{webhook_base_url}?org_id=#{connection['org_id']}</b>
        HTML
      end,

In our case, we have used an input gained from the connection called org_id which represents the specific Greenhouse organization for the connection used in this recipe. This will be important to route this webhook to the correct recipes when there are multiple connections.

To know more about the help, take a look at our SDK reference.

# Step 4 - Define input fields

This component tells Workato what fields to show to a user configuring this trigger. In this case, we want a simple input field that allows a user to pick the type of Candidate event. This will be used in our trigger code later on create the trigger's personal webhook key.

    input_fields: lambda do |object_definitions|
      [
        {
          name: 'event_type',
          label: 'Event',
          control_type: 'select',
          pick_list: 'events',
          optional: false,
          hint: 'Select specific event.'
        }
      ]
    end,

New event input fields New event input fields

Various other key value pairs exist for input/output fields other than the ones defined above. Click here to find out more.

Object definitions

Note that object_definitions is passed in as an argument. Workato allows connector builders to supply the definitions of an object separately in the "object_definitions" key. This key is used when the definitions of an object are large and/or can be dynamically obtained.

To know more about this, take a look at our SDK reference

# Step 5 - Defining the trigger webhook key

After defining the inputs from the end user, we can now move on to define the connector's webhook_key lambda function. This lambda function receives two arguments for the user's connection values as well as inputs from the input_fields of this trigger. This allows you to create a string that is a key that is specific to your webhook trigger.

With this webhook_key and webhook_keys in step 1, you now have 2 unique strings generated. When an incoming webhook is received to your connector's webhook URL, the resultant output string from the webhook_keys lambda function is matched against strings generated from webhook_key lambda functions within each trigger. If there is a match, the webhook is routed to this trigger (and all others that match).

    webhook_key: lambda do |connection, input|
      "#{connection['org_id']}@#{input['event_type']}"
    end,

In our webhook example from step 1, you can see that the webhook_keys output string would be 555@candidate_stage_change. If the output of webhook_key which utilizes the connection['org_id'] and input['event_type'] match, an event would be routed to this trigger.

# Step 6 - Defining how to handle the webhook

The webhook_notification lambda function describes what your connector should do with all webhooks routed to it. You have numerous arguments available which represent both the user's inputs to the trigger as well as the webhook itself. To send the payload of the webhook as a job, you can simply pass on the payload argument. You may also add on attributes from the headers if required. In the case of Greenhouse, we have stripped away some irrelevant details from the payload found here (opens new window).

    webhook_notification: lambda do |input, payload, extended_input_schema, extended_output_schema, headers, params|
      payload.dig('payload', 'application')
    end,

Webhook Validations

  • Workato performs validations on JSON based webhooks - denoted by the webhook's Content-Type header, to ensure that the payload is valid JSON. Otherwise, Workato responds with 400 bad request.
  • Incoming webhook payloads are expected to be UTF-8 compatible and Workato responds with 400 bad request if UTF-8 incompatible characters are found.

To know more about the webhook_key and webhook_notification key, take a look at our SDK reference

# Step 7 - Defining output fields and dedup

This section tells us what datapills to show as the output of the trigger as well as how to prevent duplicate records to create duplicate jobs. To prevent a job from being repeated (this might happen when a webhook is sent twice), use the dedup key which tells your connector how to create a unique signature for each record. This signature is stored for each recipe and if a record with the same signature is found, no job will be created.

For datapills, use the output_fields key. The name attributes of each datapill should match the keys of a single webhook payload.

    dedup: lambda do |record|
      record['id']
    end,

    output_fields: lambda do |object_definitions|
      [
        {
          name: 'id'
        },
        {
          name: 'rejected_at'
        },
        {
          name: 'prospect'
        },
        {
          name: 'prospect_detail',
          type: 'object',
          properties: [
            {
              name: 'prospect_pool',
              type: 'object',
              properties: [
                {
                  name: 'id',
                  type: 'integer',
                  control_type: 'integer'
                },
                {
                  name: 'name'
                }
              ]
            },
          ]
        }
       ]
    end,

New event output fields New event output fields

  # Sample output of the webhook_notification: lambda function
  {
    "id": "a1241",
    "rejected_at": "2020-01-12 10:57:03",
    "prospect": true,
    "prospect_detail": {
      "id": 12491,
      "name": "John Doe"
    }
  }

To know more about the output fields key, take a look at our SDK reference

Object definitions

Note that object_definitions is passed in as an argument. Workato allows connector builders to supply the definitions of an object separately in the "object_definitions" key. This key is used when the definitions of an object are large and/or can be dynamically obtained.

To know more about this, take a look at our SDK reference

# Step 8 - Defining sample output

A optional supplementary component to the trigger, the sample output key nonetheless greatly improves a user's experience by giving him/her some context to what the datapill's value could be. This allows users to build recipes more quickly.

    sample_output: lambda do |connection, input|
      if input['event_type'] == "candidate_stage_change"
        get("v1/applications?per_page=1")&.dig(0) || {}
      else
        get("v1/#{input['object']&.pluralize}?per_page=1")&.dig(0) || {}
      end
    end

To know more about the sample output key, take a look at our SDK reference

# Step 9 - Secure your webhook events

Now that you're receiving webhooks, you can now consider adding additional checks to verify the authenticity of incoming webhook events.

# Rate limits

This trigger is subject to our webhook gateway's limits.


Last updated: 2/6/2024, 3:17:30 AM