Webhook Forwarding deep-dive

Webhook Relay provides public endpoints which can accept webhooks and then, based on user defined rules, forward them to either public or internal destinations.

Our service has a concept of bucket which is basically a grouping mechanism that enables you to accept webhooks on multiple endpoints and forward them to one or more destinations. Bucket inputs are configurable and can return custom responses, while outputs can have filtering rules and forward webhooks to both internal or public destinations:

Webhook routing

Using configuration helpers

We have a step-by-step configuration wizards that will help you:

Once configuration is created, you can always edit all details by visiting your buckets page.

Configuring manually

A newly created bucket will have a default input and you will need to create an output destination.

New Bucket

To do that, click on OUTPUT DESTINATIONS. If it’s a public destination, add the name, HTTP URL and click ‘create output’. All received webhooks will be forwarded to that destination.

If it’s an internal destination, check ‘internal network’ and start a relay agent:

$ relay forward --bucket new http://localhost:8080
Forwarding: 
https://vlndyzsibcil98gdte7l3r.hooks.webhookrelay.com -> http://localhost:8080

What can be forwarded?

Currently Webhook Relay forwards:

  • Body (up to 3MB)
  • Headers
  • URL query, for example https://vlndyzsibcil98gdte7l3r.hooks.webhookrelay.com?foo=bar, will be forwarded to http://localhost:8080?foo=bar
  • Extra path that’s after your public input endpoints: https://vlndyzsibcil98gdte7l3r.hooks.webhookrelay.com/directory/foo will be forwarded to http://localhost:8080/directory/foo

Ephemeral webhooks (no logs)

Buckets can be configure to be ephemeral so that request method, headers, query and body will not be saved to the database. To do this, go to bucket details page, click on SETTINGS tab and tick Ephemeral webhooks checkbox. All new webhooks will not have their details saved. When ephemeral mode is on, you will not be able to:

  • view request details
  • resend webhook

New webhook logs will appear like this:

Ephemeral logs

Static or Dynamic response body settings

Sometimes applications that send webhooks accept certain headers, status code or body. To configure these settings, go to your bucket details and click on a CONFIGURE button:

Input URL response settings

Now, if you scroll down to Response configuration section, you will be able to:

  • For dynamic responses select which (or any) output should respond to the caller
  • For static responses, enter your preference in the “Static responses section”

Input URL response configuration

Note: dynamic responses work for both public and internal endpoints as long as they respond within 10 seconds. Another option for responses are using functions.

Dynamic responses from Functions

Functions, when applied on Inputs can provide dynamic response. See Function examples.

Overriding webhook headers, timeouts, TLS verification

Output configuration allows overriding request headers so users can add any headers on top. To view output settings, go to outputs tab in bucket details and click CONFIGURE on any output:

Configure output

You can also update output destination and headers through CLI:

relay output update OutputName --bucket Test --header secret-token=123456 --destination https://127.0.0.1:1880

Request matching rules

Rules can be applied on each output to filter incoming requests. There are a number of different configurations that allow:

  • Match based on request body contents (such as contains, does not contain rule types)
  • Match based on parsed JSON body
  • Regex match based on URL query, headers or parsed JSON body
  • Simple equality check based on URL query, headers or parsed JSON body

To start using rules, go to output details page. Below, there are several examples to do matching based on URL queries and request bodies.

Matching based on URL query

Value match

Let’s create a rule that checks whether URL query has a specific parameter that matches our given value:

Configure URL match based on value

With this configuration, if we send a webhook to https://my.webhookrelay.com/v1/webhooks/aa4d6bb5-87b6-4041-b5f4-a768338425c6?name=john, rule will extract and match parameters name=john.
While https://my.webhookrelay.com/v1/webhooks/...?name=john will be matching the rule, a webhook to https://my.webhookrelay.com/v1/webhooks/...?name=tom will not be relayed.

Regular expressions

To match based on regular expressions, select regex rule type:

Configure URL match based on regular expression

With this configuration, a webhook request query will have to have a location parameter with value either london or paris: https://my.webhookrelay.com/v1/webhooks/...location=paris

You can view regex examples here: https://golang.org/pkg/regexp/syntax/

Contains or Does Not Contain

There are additional matching types such as contains and does not contain. These are general purpose, easy to use matchers.

Matching based on request body

Body matching can be achieved by:

  • value based matching
  • regex matching of parsed body into a JSON object
  • contains matching that looks for a specified text in the body
  • does not contain matching that checks whether body doesn’t have a specified word/phrase

value

Value type rule can match a parsed payload of a JSON webhook and check whether a specified parameter matches the rule value:

Configure body match based on value

Only webhooks that have id = foo inside the nested ‘data’ key will be passed:

{
    "status": "xx",
    "data": {
        "id": "foo"
    }
}

Match ‘does not contain’

Regex rules can match based on specified parameters when JSON body is parsed:

Does not contain for request body

With this configuration, a request with payload:

{
    "status": "xx",
    "data": {
        "id": "xxx"
    }
}

will be matched by a rule and passed through, while this one:

{
    "status": "ff",
    "data": {
        "id": "foo"
    }
}

will be rejected as it contains our unwanted value.

Match ‘contains’

Contains matching is one of the simplest examples:

Configure body match based on phrase

Select a contains rule type and type a string that should be in the request body:

{
    "status": "ff",
    "data": {
        "id": "london"
    }
}

This payload will be relayed.

If body is not JSON, ‘contains’, ‘regex’ or ‘does not contain’ will be matching against plain text body.

Matching based on request headers

Similarly to URL query and request body matching, header rules can extract and compare values from headers:

Header rules

Validating webhook SHA1 and SHA256

Rules can perform both SHA1 and SHA256 webhook payload signature validation. For that, you need to choose header as the source, set parameter to the name of the header that will have the hash, select either ‘payload SHA1’ or ‘payload SHA256’ from the menu and set your secret in the value field:

SHA1 validation

Grouping rules

Rules can be grouped using logical operators all and any which are equivalent to and and or if you are familiar with programming principles. You can have multiple levels of rules interacting with each other.

Custom domains

Webhook Relay allows using both your own domain names or registering subdomains under .hooks.webhookrelay.com.

Using your own DNS

Instead of having input endpoints such as https://my.webhookrelay.com/v1/webhooks/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX you can reserve your own subdomains either under *.hooks.webhookrelay.com domain or use your own such as hooks.example.com.

The first time you are using a custom domain for your inputs, you will need to go to domains reservation page and click on RESERVE DOMAIN. Enter your domain and click SUBMIT.

Now, go to your bucket details page and click CONFIGURE on an input. Here, select your reserved domain from a dropdown and it’s also a good practice to enter a path prefix for your input as you can have any number of inputs (even from different buckets) sharing the same domain:

Custom domain

Finally, go to your DNS provider and create a CNAME record for your chosen domain pointing at hooks.webhookrelay.com. In this case we are using Cloudflare to add the configuration:

Cloudflare CNAME

When you send the first HTTP request to the newly configured subdomain, Webhook Relay will provision a certificate.

Custom subdomains under Webhook Relay domain

If you don’t have your own domain name but still want to have a custom subdomain that’s not randomly generated, you can reserve one under .hooks.webhookrelay.com. For example if I reserve one api.hooks.webhookrelay.com, I can use it in my Input settings:

Custom subdomain under .hooks.webhookrelay.com

and set path to /dogs so I can reuse it for multiple inputs. Now, in the response configuration let’s add some custom response such as:

[
 {
   "name": "Beethoven"
  }
]

And if you curl the endpoint (just replace the URL with your own reserved domain):

curl https://api.hooks.webhookrelay.com/dogs
[
 {
   "name": "Beethoven"
  }
]