---
title: Webhook
url: https://www.tines.com/docs/actions/types/webhook/
updated: 2026-04-21T14:36:00+00:00
---

*[tines.com](https://www.tines.com/llms.txt) › [Docs](https://www.tines.com/llms.txt) › [Actions](https://www.tines.com/llm/docs/actions.md) › [Types](https://www.tines.com/llm/docs/actions/types.md)*

# Webhook

*[View on tines.com](https://www.tines.com/docs/actions/types/webhook/)*

The Webhook Action will emit Events it receives through Webhooks (HTTP callbacks).

Webhooks are a common way for web applications to notify users of important occurrences. Use the Webhook action to receive alerts from SIEM; get notified when a developer performs a 'git push'; when a user updates a Jira ticket; or when a user posts in Slack.

To create a new webhook address, simply drag on a Webhook Action to create a URL which can receive HTTP data.

[Video](https://stream.mux.com/ojQuxgKB1fsTDDXnt9HCw3fsBzRuJc8i/high.mp4)

## 
Features

- Each Webhook Action has a unique URL.
- Specify a path and a secret that must be included in the Webhook in order for an Event to be emitted.
- Accept Webhooks using a variety of HTTP methods, e.g.: POST and GET.
- Webhook parameters will be used to generate and emit a new Event.
- Specify a custom response message, response code and response headers when Event is successfully emitted.
- Include incoming headers from HTTP requests.

## Configuration options

- `path` - A path for the webhook URL, in plain text.
- `secret` - (Optional) A token that the host will provide for authentication.
- `access_control` (Optional) Whether the webhook should be public, available only with the secret, OAuth, or using Tines API Keys (see Authentication section below).
- `verbs` - (Optional) Comma-separated list of HTTP verbs your action should accept.
- `response` - (Optional) The response message to the request. Defaults to 'Ok'.
- `response_code` - (Optional) The HTTP response code to the request. Defaults to `201`.
- `response_headers` - (Optional) An object with any custom response headers. (example: `{"Access-Control-Allow-Origin": "*"}`)
- `include_headers` - True by default, include headers from the request in a `headers` key while the body of the request is nested under a `body` key.
- `match_rules` - Specify the rules to match against body or headers in the request.
- `must_match` - Specify the number of rules that must match.
- `capture_raw_body` - Capture and emit the raw body of the incoming request.
- `rate_limit` - Rate limit requests to the webhook. See the Rate Limiting section below.

## Emitted events

The Webhook Action will convert the Webhook payload into a Tines Event.

Technical notes

- When an array, boolean, string, or anything besides an object is sent as the request payload and the content type is JSON, (e.g., from an HTTP Request Action with a JSON content type), the resulting event from the webhook is automatically wrapped in an object with a `_json` key. The `body` object will contain `{"_json": [...]}` instead of the array directly. To access the array, use `body._json`.
- When making requests with headers who's keys contain dashes `-` or capital letters in them to webhooks, the resulting events generated from the webhook will interpolate those dashes as underscores* *and downcase the letters in the keys only, values remain unchanged (e.g., an HTTP Request Action with a header key: `X-Example-Id` and value: `AB-C` will have an event emitted by the webhook with `"x_example_id": "AB-C"`.

## Authentication and authorization

There are a few methods for authenticating a webhook. The primary one is using webhook secrets: a random string assigned to each webhook.

Another option is to use OAuth, scoping access to either the Team or the Tenant. If you select OAuth, the user will be redirected to your Tines tenant to grant consent when adding the MCP server to their client.

Alternatively, you can set the Access Control for the webhook to be "Team" or Tenant", and use Tines API Keys passed in via the `Authorization` HTTP header.

### Secrets in URL

By default, webhook requests are authenticated by the Webhook Action `secret`. This is passed to the Webhook Action via as part of the webhook URL: `https://tenant.tines.com/webhook/<path>/<secret>`.

Secrets are not part of the path for webhook actions with an [API path prefix](https://tines.com/docs/actions/types/webhook/#api-path-prefix). You can just remove the secret field from the action if you don't want a secret to be required for this endpoint. To provide a secret in the URL for those stories, you can use a query param: `https://tenant.tines.com/api/public/<api_name>?secret=<secret>`

### Access control

There are four access control options

- Public: Anyone with the path (no secret or authentication is enforced)
- Secret: Anyone with the secret (default method)
- Team: Only team members (regardless of role)
- Tenant: Members of this Tines tenant (regardless of role)

When configuring Team or Tenant access control, the only way to authenticate is to provide a valid Tines API Key with each request. When an API Key is provided, the email of the API Key's owner will be attached to the `email` key in the `headers` of the emitted event.

> **IMPORTANT:** If you created a Tines API key using a connect flow and want to use it for webhooks, you need to add an extra allowed URL for `<your-tenant>/webhook/*` on the credential restrictions.

### Authorization HTTP header

If you wish to use the HTTP `Authorization` header you can pass the Webhook Action `secret`  or API Key (depending on the access control opion) as the credential using a `Basic` or `Bearer` auth scheme:

```bash
curl -H "Authorization: Bearer <secret>" https://tenant.tines.com/webhook/<path>
```

### Signatures

An alternative to sending the `secret` with every request is to sign your webhook request with the `secret`. The process to signing each request is as follows:

- Generate a timestamp, milliseconds or seconds from epoch works great.
- Concatenate the timestamp into a String of the format `<timestamp>.<webhook URL>.<request body>` where:
  
  - `timestamp` is the timestamp in numeric format. For example, `1686567186`
  - Followed by the `.` character
  - `webhook URL` is the full URL of the webhook, including query parameters. For example, `https://tenant.tines.com/webhook/<path>`
  - Followed by the `.` character
  - `request body` is the raw body of a HTTP POST request. This can be left blank for HTTP GET requests
- Compute an HMAC of the concatenated String with the SHA256 hash function. Use the Webhook Action `secret` as the key.
  
  - For example, you could use the `HMAC_SHA256()` [Tines function](https://www.tines.com/docs/formulas/functions/hmac-sha256/) or the Open SSL example below.
- Add the timestamp and the result to the `X-Tines-Signature` HTTP header in the format: `ts=<timestamp>;sig1=<hmac>`.



Here are some examples for HTTP GET and POST requests:

**GET**

```bash
TS=$(date +%s)

URL="https://tenant.tines.com/webhook/<path>?foo=bar"

SIG=$(echo -n "$TS.$URL." | openssl dgst -sha256 -hmac <secret>)

curl $URL -H "X-Tines-Signature: ts=$TS;sig1=$SIG"
```

**POST**

```bash
TS=$(date +%s)

URL="https://tenant.tines.com/webhook/<path>"

BODY="{'foo': 'bar'}"

SIG=$(echo -n "$TS.$URL.$BODY" | openssl dgst -sha256 -hmac <secret>)

curl -X POST $URL -H "X-Tines-Signature: ts=$TS;sig1=$SIG" -d $BODY
```

## Example configuration options

Receive GET and POST requests when the correct `path` and `secret` is supplied

![](https://www.datocms-assets.com/55802/1715094369-screenshot-2024-05-07-at-16-05-20.png)

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post"
}
```

Receive POST requests and respond with a custom `response`, `response_code `and `response_headers`. Response values and headers can be added by selecting them from the options dropdown.

![](https://www.datocms-assets.com/55802/1715094523-screenshot-2024-05-07-at-16-07-19.png)

![](https://www.datocms-assets.com/55802/1715094607-screenshot-2024-05-07-at-16-10-00.png)

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post",
  "response": "Thank you!",
  "response_code": 200,
  "response_headers": {
    "X-Tines-Response": "Event emitted"
  }
}
```

Respond with data contained in a resource. Allowed content types are `text/plain`, `text/xml`, and `application/json`.

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post",
  "response_headers": {
    "content-type": "application/json"
  },
  "response": "<<RESOURCE.ip_list>>"
}
```

Respond to webhook verification challenges using data received by the webhook in the request headers or body. In the example below, the `headers` key refers to the headers from the incoming request. Similarly, `body` can be used to access the body of the incoming request.

![](https://www.datocms-assets.com/55802/1715094686-screenshot-2024-05-07-at-16-11-13.png)

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post",
  "response": {
    "verification": "<<headers.x_okta_verification_challenge>>"
  }
}
```

The feature described above is useful when the incoming request contains information that it expects to receive in the response. For example, [some Slack API endpoints](https://api.slack.com/events/url_verification) include a `challenge` field. Unless the response to that request includes the same `challenge` field, slack will not trust the webhook. You can fulfil this requirement by accessing the challenge value through the `body` field.

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post",
  "response": {
    "challenge": "<<body.challenge>>"
  }
}
```

Redirect requests to another address while still recording the data payload.

```json
{
  "path": "eb7f40dbc217bfd8c4a5a843611a3b2d",
  "secret": "c9e648cdf08204c3aa9784fe2efa2e61",
  "verbs": "get,post",
  "response": "https://www.google.com",
  "response_code": "302"
}
```

## Response-enabled webhooks

In stories with the** **`Enable webhook API responses`** **[option](https://www.tines.com/docs/stories/apis/) enabled, the response from the webhook will be event emitted from the first `Exit action` reached in the story, as long as that action is executed within 30 seconds.

No more than 100 webhook-enabled concurrent responses can be processed simultaneously (1000 in dedicated tenants). When this limit is exceeded, the webhook action will fall back to responding immediately with the `response` it has configured.

### API path prefix

Response-enabled webhooks also have the option to provide an `API path prefix`. This special option allows the response-enabled webhook to be called via an API-style path: `https://tenant.tines.com/api/public/<api-path-prefix>`. You can include subpaths, and they will be included in webhook action's event data at `body.api_path`.

## Custom domain for webhooks

> **TIP:** To enable custom domains on your webhooks (and pages), [reach out to the Tines team](https://www.tines.com/contact-support/) to learn more.

With a custom domain enabled, all webhooks (including webhooks in existing stories built prior to the configuration of a custom domain) will be switched to the custom domain for their webhooks. However, the webhooks will still be accessible via their original URL. Please refer to [Custom domain for pages](https://www.tines.com/docs/custom-domain-for-pages/) for information about how custom domains affect pages.

## Webhook rules

Webhook Rules allow you to specify criteria that must be met in order for an event to be emitted. The Tines Webhook Action can parse the request body and/or headers to meet these criteria. An event is created only when a rule is matched, and the matching rule is included in the `meta` object of the event. If no rule is matched, a `No Rules Matched` response is returned to the client.

In the following example, we are checking if an HTTP header named `X_HTTP_EXAMPLE` is equal to the value `foo` or if the JSON request body has a nested object where the key `foo` equals the value `bar` using dot notation.

```json
{
  "path": "4d4217f7e94467ee3dec675189566f9a",
  "secret": "a409cd0d15a079ee69873aaa5b2e3d04",
  "verbs": "get,post",
  "must_match": 1,
  "rules": [
    {
      "type": "field==value",
      "value": "foo",
      "path": "headers.X_HTTP_EXAMPLE"
    },
    {
      "type": "field==value",
      "value": "bar",
      "path": "body.object_example.foo"
    }
  ]
}
```

[Demo](https://stream.mux.com/B3u9W5AspT1oK1Mi02gTe1zcoU2YOuhXG/high.mp4)

## Rate Limiting

Requests to your webhook action can be rate limited using any attribute from the HTTP headers and/or body. This is a great way to ensure that your webhook is not overwhelmed by requests. The `rate_limit` action option takes three parameters:

• `key`: The value to track. This can be from headers, body, or any formula.

• `count`: The maximum number of requests allowed for the value of `key`, for the time window specified in `period`.

• `period`: The time window in seconds during which it will check the count for the evaluated key.

The rate limit is checked for every request, and if the count is exceeded the request is rejected with a default `429` status code.
