> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vatis.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Listen to events on your resources with webhooks.

## Overview

When integrating the Vatis Streams API you may need to listen to events on your resources, so your application can react accordingly.
To do this, you can register a webhook endpoint containing the URL where you want to receive the events and the type of events the endpoint is listening to.
When an event is triggered, a `POST` request will be sent to all the registered endpoints with the event data.

## Setup

Manage your webhooks through the [API Dashboard](https://vatis.tech/app/playground/webhooks).

## Webhook structure

The webhook endpoint you can define will have the following structure:

```json theme={null}
{
  "id": "<string>",
  "url": "<string>",
  "events": [
    "<string>"
  ],
  "enabled": true,
  "description": "<string>"
}
```

| Property      | Description                                                                                                             |
| ------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `id`          | The webhook endpoint identifier                                                                                         |
| `url`         | The URL where the events will be sent. Accepted protocols: `HTTP`, `HTTPS`                                              |
| `events`      | The list of event types the endpoint is listening to. Check the avaiable event types [here](#event-types)               |
| `enabled`     | Indicates if the webhook is enabled. You can disable an endpoint to temporarily stop receiving requests to the endpoint |
| `description` | An optional description of the webhook                                                                                  |

<Warning>Local IP addresses and loopback interfaces are not allowed in the `url`</Warning>

## Event structure

The webhook event you'll receive will have the following structure:

```json theme={null}
{
  "id": "<string>",
  "type": "<string>",
  "webhookEndpointId": "<string>",
  "timestamp": "<long>",
  "payloadSchema": "<string>",
  "payload": "<object>"
}
```

| Property            | Description                                                                         |
| ------------------- | ----------------------------------------------------------------------------------- |
| `id`                | The event identifier                                                                |
| `type`              | The event type. Check the avaiable event types [here](#event-types)                 |
| `webhookEndpointId` | The webhook endpoint identifier                                                     |
| `timestamp`         | The event timestamp in milliseconds since epoch. Use this to prevent replay attacks |
| `payloadSchema`     | The fully qualified name of the payload schema                                      |
| `payload`           | The event payload                                                                   |

## Event types

| Event type             | Supports dynamic webhooks | Description                                                                                                                                      |
| :--------------------- | :-----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `stream.ready`         |            yes            | The stream has just been created and is ready to receive data                                                                                    |
| `stream.completed`     |            yes            | The stream completed successfully                                                                                                                |
| `stream.failed`        |            yes            | The stream failed                                                                                                                                |
| `stream.expired`       |            yes            | The stream storage time expired and it was deleted                                                                                               |
| `group.created`        |            yes            | A new group has been created                                                                                                                     |
| `group.completed`      |            yes            | All the streams in the group completed successfully. This event will be emitted again if a new stream joins the group and completes              |
| `group.failed`         |            yes            | All the streams in the group finished and at least one stream failed. This event will be emitted again if a new stream joins the group and fails |
| `group.expired`        |            yes            | The group storage time expired and it was deleted. A group will expire only after all the streams in the group had expired                       |
| `group.stream-joined`  |            yes            | A new stream has joined the group                                                                                                                |
| `gateway.connected`    |             no            | A client connected to the stream gateway                                                                                                         |
| `gateway.disconnected` |             no            | The client disconnected from the stream gateway                                                                                                  |
| `gateway.closed`       |             no            | The gateway of the stream is permanently closed                                                                                                  |
| `gateway.error `       |             no            | The gateway of the stream is permanently closed due to an error                                                                                  |
| `processor.running`    |             no            | The stream processor has been assigned to stream and it is running                                                                               |
| `processor.completed`  |             no            | The stream processor has been completed successfully                                                                                             |
| `processor.error`      |             no            | The stream processor has failed                                                                                                                  |

## Source IPs

To make sure your server is able to receive the events, you can **whitelist** the following IP addresses:

* `Europe`: `52.59.67.134`

## Redelivery

If the server does not respond with a `2xx` status code, the event redelivery will be retried for the next three hours with an exponential backoff strategy.

## Development

For experimenting the webhook integration on a local environment, you can create the setup described below.

<Accordion title="Setup steps">
  <Steps>
    <Step title="Install ngrok">
      <Tabs>
        <Tab title="Linux (Apt)">
          ```bash theme={null}
           curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok
          ```
        </Tab>

        <Tab title="Linux (Snap)">
          ```bash theme={null}
          snap install ngrok
          ```
        </Tab>

        <Tab title="Mac">
          ```bash theme={null}
          brew install ngrok/ngrok/ngrok
          ```
        </Tab>

        <Tab title="Windows">
          ```bash theme={null}
          choco install ngrok
          ```
        </Tab>
      </Tabs>

      Alternatively, you can download the executable from the [official website](https://ngrok.com/download)
    </Step>

    <Step title="Install Nginx">
      <Tabs>
        <Tab title="Linux (Apt)">
          ```bash theme={null}
          apt install nginx
          ```
        </Tab>

        <Tab title="Mac">
          ```bash theme={null}
          brew install nginx
          ```
        </Tab>

        <Tab title="Windows">
          Download the installer from the [official website](https://nginx.org/en/download.html)
        </Tab>
      </Tabs>
    </Step>

    <Step title="Configure Nginx">
      <Tabs>
        <Tab title="Linux">
          ```bash theme={null}
          cat <<EOF > /etc/nginx/conf.d/dev-webhook.conf
          server {
            listen 8081;
            server_name localhost;

            location /200 {
              add_header Content-Type text/plain;
              return 200 "200 - OK";
            }

            location /400 {
              add_header Content-Type text/plain;
              return 400 "400 - ERROR";
            }

            location /500 {
              add_header Content-Type text/plain;
              return 500 "500 - SERVER ERROR";
            }
          }
          ```
        </Tab>

        <Tab title="MacOS">
          ```bash theme={null}
          cat <<EOF > /opt/homebrew/etc/nginx/servers/dev-webhook.conf
          server {
            listen 8081;
            server_name localhost;

            location /200 {
              add_header Content-Type text/plain;
              return 200 "200 - OK";
            }

            location /400 {
              add_header Content-Type text/plain;
              return 400 "400 - ERROR";
            }

            location /500 {
              add_header Content-Type text/plain;
              return 500 "500 - SERVER ERROR";
            }
          }
          ```
        </Tab>
      </Tabs>
    </Step>

    <Step title="Prepare the tunnel">
      ```bash theme={null}
      nginx
      ngrok http 8081
      ```
    </Step>

    <Step title="Create/update the webhook">
      Create or update the webhook endpoint URL with the temporary URL provided by ngrok.
      Choose one of the following as URL paths, based on the test you want to perform:

      * `/200`
      * `/400`
      * `/500`
    </Step>

    <Step title="Monitor requests">
      Open the Ngrok dashboard at [http://localhost:4040](http://localhost:4040) to monitor the requests.
      Create a new stream or group to trigger the events.
    </Step>
  </Steps>
</Accordion>

## Considerations

1. A user can define up to 20 webhook endpoints
2. The same event may be sent multiple times to the same endpoint
3. The order of the events is not guaranteed

## Dynamic webhooks

A dynamic webhook is a webhook defined on a resource basis. In contrast to a standard webhook that is defined once and can be triggered by any resource (group, stream, gateway, etc.) based on the event key,
a dynamic webhook is associated with a specific resource and it can be triggered only by that resource.

The main advantage of a dynamic webhook is the ability to modify the endpoint URL for each created stream. For example, we can include a unique identifier in the endpoint URL that changes for each created stream.

### All gateways

For each available gateway, a dynamic webhook can be defined as a query parameter that follows this general syntax: `webhook[.RESOURCE[.STATE]]=<url>`

For example:

* `webhook.stream.completed=https://mydomain.com/success` will create a dynamic webhook the receives the `stream.completed` event at the `https://mydomain.com/success` URL
* `webhook.stream.completed=https://mydomain.com/success&webhook.stream.failed=https://mydomain.com/fail` will create two dynamic webhooks, one that will be triggered by the `stream.completed` event at the `https://mydomain.com/success` URL,
  and the other that will receive the `stream.failed` event at the `https://mydomain.com/fail` URL
* `webhook.stream.completed=https://mydomain.com/status&webhook.stream.failed=https://mydomain.com/status` will create a single dynamic webhook that will be triggered by both `stream.completed` and `stream.failed` events
  at the `https://mydomain.com/status` URL
* `webhook.stream=https://mydomain.com/stream-event` is a wildcard dynamic webhook that be triggered by any stream-related event at the `https://mydomain.com/stream-event` URL
* `webhook=https://mydomain.com/any-event` is a wildcard dynamic webhook that will be triggered by any event at the `https://mydomain.com/any-event` URL

### Websocket Gateway

Additionally to the dynamic webhooks defined using query parameter, the `WebSocket Gateway` can receive the dynamic webhooks configuration using the [Configuration Message](/integration/websocket#configuration).

The general form of the webhook configuration is as follows:

```json theme={null}
{
  "type": "CONFIGURATION",
  "webhook": {
    "https://mydomain.com/success": ["stream.completed"],
    "https://mydomain.com/fail": ["stream.failed"],
    "https://mydomain.com/status": ["stream.completed", "stream.failed"],
    "https://mydomain.com/stream-event": ["stream.*"],
    "https://mydomain.com/any-event": ["*"]
  }
}
```

<Warning>Please use either the query parameters or the configuration message for defining the dynamic webhooks. If both are specified, the behaviour is undefined.</Warning>

### Limitations

* Only `stream` and `group` resources can be used in dynamic webhooks
* No more than 3 dynamic wehooks can be defined
* The supported endpoint protocols are `http` and `https`
