# How-to guides - Static Webhook Trigger

A static webhook trigger is one that requires manual registration. This usually involves a user creating a webhook in the application user interface with a pre-defined webhook URL. It defers from a dynamic webhook because it requires a fixed webhook URL for use in the manual registration process, instead of having it be done in the background (programmatic subscription through the API when a user starts a recipe).

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|
      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: "Triggers when webhook is sent from Greenhouse. First, " \
            " select the event you want to trigger this recipe, then configure these webhooks in" \
            " Greenhouse to match the webhook URL of this custom connector.",

      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|
          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 key for each incoming webhook. For example:

  • With this definition
    webhook_keys: lambda do |params, headers, payload|
      payload['action']
    end,
  • and an incoming webhook with the following shortened body from Greenhouse
{
  "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 for this webhook payload should be 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, description, and help

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. Finally, the help segment provides users any additional information required to make the action work.

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

# Step 3 - 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 4 - Defining the trigger webhook key and webhook handling

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).

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_key: lambda do |connection, input|
        input['event_type']
    end,

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

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

# Step 5 - 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 6 - 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