Skip to content

Integrations setup

Integrations can be configured only via the YAML file!

Also, don't forget to restart the Kuvasz container after modifying the YAML file for the changes to take effect!

Don't want your webhook URLs and API keys in your YAML file?

Since integrations are typically full of sensitive data, you might want to check the Keeping secrets out of your configuration file recipe, which shows you how to reference environment variables from your YAML file, or how to move your integrations into a separate, secret file.

Your integrations are the channels through which Kuvasz sends notifications about the status of your monitors. You can use Kuvasz without any integrations, but it won't make much sense in most of the cases, because you won't be notified about any issues with your monitors.

Where to put them exactly?

You're free to put your integrations under integrations: in your YAML configuration file, wherever you like. The only restriction is that under integrations you can only use the integration types that are supported by Kuvasz.

How can they be referenced?

You can reference your integrations in your monitors by their ID, which is always dynamically generated by concatenating the type and name of the integration, separated by a colon (:). For example, if you have a Slack integration with the name slack-example, its ID will be slack:slack-example.

Common settings

All the integrations share some common, generic settings , which means that it doesn't matter which integration you configure, you can use the same settings for all of them.

Name

2.0.0 string name

The name of the integration. It must be unique across the given type of integration, so you can have multiple Slack integrations, for example, but they must have different names, and vice versa: you can have multiple integrations of different types with the same name. Can't be a blank string!

integrations:
  pagerduty:
    - name: "PD global integration"
      integration-key: YourOwnIntegrationKey

Enabled

2.0.0 true boolean enabled

Whether the integration is enabled or not. If it's set to false, the integration won't be used, and no notifications will be sent through it, however you can still reference it in your monitors.

integrations:
  pagerduty:
    - name: pd_global
      enabled: true
      integration-key: YourOwnIntegrationKey

Global

2.0.0 false boolean global

Whether the integration is global or not. If it's set to true, the integration will be used for all monitors by default, even if they don't have a specific integration assigned to them. If it's set to false, the integration will only be used for monitors that explicitly reference it.

integrations:
  pagerduty:
    - name: pd_global
      global: true
      integration-key: YourOwnIntegrationKey

Excluded events

3.8.0 empty list excluded-events

Integrations are listening to every event by default, but you can configure them to exclude specific events if you don't want to receive notifications for them.

The valid options are the following:

  • HTTP_UP
  • HTTP_DOWN
  • PUSH_UP
  • PUSH_DOWN
  • SSL_VALID
  • SSL_INVALID
  • SSL_WILL_EXPIRE
  • ICMP_UP
  • ICMP_DOWN
  • TCP_UP
  • TCP_DOWN
  • DNS_UP
  • DNS_DOWN
  • DNS_RECORDS_CHANGED

In case you don't specify any event types, or you provide an empty list, the integration will receive all the events.

integrations:
  pagerduty:
    - name: pd_global
      global: true
      excluded-events:
        - PUSH_DOWN
        - PUSH_UP
        - SSL_WILL_EXPIRE
      integration-key: YourOwnIntegrationKey

Slack

Configuration alias: slack

The Slack integration allows you to send notifications to a Slack channel via a webhook URL.

Webhook URL

2.0.0 string webhook-url

The webhook URL of the Slack channel where the notifications will be sent. You can create a webhook URL in your Slack workspace by following the official documentation.


Slack integration example
integrations:
  slack:
    - name: slack-example
      webhook-url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXX'
    - name: slack-global
      webhook-url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXX'
      global: true
    # ... other Slack integrations

Discord

Configuration alias: discord

The Discord integration allows you to send notifications to a Discord channel via a webhook URL.

Webhook URL

2.3.0 string webhook-url

The webhook URL of the Discord channel where the notifications will be sent. You can create a webhook URL in your Discord server by following these steps:

  1. Go to your Discord server settings
  2. Navigate to Integrations → Webhooks
  3. Click New Webhook
  4. Configure the webhook name and select the target channel
  5. Copy the Webhook URL

For more information, see the official Discord documentation.


Discord integration example
integrations:
  discord:
    - name: discord-example
      webhook-url: 'https://discord.com/api/webhooks/123456789/abcdef1234567890abcdef1234567890'
    - name: discord-global
      webhook-url: 'https://discord.com/api/webhooks/987654321/fedcba0987654321fedcba0987654321'
      global: true
    # ... other Discord integrations

Microsoft Teams

Configuration alias: ms-teams

The Microsoft Teams integration sends notifications to a Teams channel or chat as an Adaptive Card, color-coded by the severity of the event.

Workflows only, not the retired Microsoft 365 Connectors

Microsoft is retiring Microsoft 365 (Office 365) Connectors, so their https://<tenant>.webhook.office.com/... URLs are not supported. Use the Workflows app (powered by Power Automate) instead, as described below.

Webhook URL

4.3.0 string webhook-url

The URL of the Teams workflow the notifications will be sent to. To create one:

  1. In Microsoft Teams, go to the team and channel where you want to receive the notifications
  2. Select More options (...) next to the channel, then Workflows
  3. Search for and select the Send webhook alerts to a channel template
  4. Configure the workflow parameters, then select Save
  5. Copy the webhook URL the workflow generated

For more information, see the official documentation.

Treat the URL as a secret

Anyone who has the URL can post messages to the channel, since it carries its own signature and needs no further authentication. Check the examples on how to keep it out of your configuration file.


Microsoft Teams integration example
integrations:
  ms-teams:
    - name: ms-teams-example
      webhook-url: 'https://prod-11.westeurope.logic.azure.com:443/workflows/.../triggers/manual/paths/invoke?...'
    - name: ms-teams-global
      webhook-url: 'https://prod-22.westeurope.logic.azure.com:443/workflows/.../triggers/manual/paths/invoke?...'
      global: true
    # ... other Microsoft Teams integrations

A successful request doesn't guarantee a delivered message

The workflow's trigger accepts the request eagerly, answering with an empty 202 Accepted before the flow itself runs. Kuvasz therefore logs the notification as sent even when the flow fails afterwards, for example because it was turned off. If a card never shows up in the channel despite a successful test, check the run history of the workflow in Power Automate.

Apprise

Configuration alias: apprise

Apprise API is a self-hosted REST gateway that forwards a single notification to 80+ services at once - Slack, Discord, Telegram, ntfy, Gotify, Matrix, Pushover, email, SMS providers and many more. Instead of configuring each of them in Kuvasz separately, you can hand the notification to Apprise and let it fan out.

The notifications are sent with a title, a body and a type that carries the severity of the event, which Apprise translates to whatever the target service understands: the color of a Discord embed, the priority of an ntfy message, or the icon of a desktop notification.

Event Apprise type
A monitor or a certificate recovered, a maintenance window ended success
A monitor went down, a certificate became invalid failure
A certificate is about to expire warning
DNS records drifted, a maintenance window started info

URL

4.3.0 string url

The notify endpoint of your Apprise API instance. Apprise can be used in two ways, and this URL decides which one you get:

  • Stateful: you store your service URLs in Apprise under a key (e.g. POST /add/kuvasz), then point Kuvasz at http://your-apprise-host:8000/notify/kuvasz. No secrets end up in the Kuvasz configuration, which is why this is the recommended setup.
  • Stateless: you point Kuvasz at http://your-apprise-host:8000/notify and list the target services in target-urls instead. Nothing is persisted on the Apprise side, so it needs no volume.

Target URLs

4.3.0 empty list target-urls

The Apprise service URLs the notifications should be delivered to, for the stateless mode. Leave it empty when you use a stored configuration.

Every entry is an Apprise URL, not a regular one - slack://TokenA/TokenB/TokenC, tgram://bottoken/ChatID, ntfy://topic, and so on. The full list of the supported formats is in the Apprise wiki.

Treat these URLs as secrets

Apprise service URLs embed the tokens of the target services, so anyone who has them can post messages in your name. Check the examples on how to keep them out of your configuration file, or avoid the problem entirely by using the stateful mode.

Tag

4.3.0 string tag

Routes the notifications to a subset of a stored Apprise configuration, for the stateful mode. Only makes sense if the entries of your configuration are tagged.

Apprise has its own little grammar here, where a comma means OR and a space means AND:

Value Matches
devops the entries tagged devops
devops, oncall the entries tagged devops or oncall
devops critical the entries tagged devops and critical
devops critical, oncall the entries tagged (devops and critical) or oncall
all every entry, tagged or not

Leaving it empty does not mean everything

When no tag is given, Apprise matches the notification against the untagged entries only. So if every entry of your stored configuration is tagged, nothing is delivered and Apprise answers with a 424 Failed Dependency, which shows up as a failed notification in the Kuvasz logs.

Set tag: all to reach every entry regardless of its tags.

Note that this only affects the stateful mode: on the stateless endpoint Apprise itself defaults to all, so the same Kuvasz configuration behaves differently in the two modes.

Request headers

4.3.0 empty map request-headers

Optional HTTP headers that will be included in the requests sent to your Apprise instance.

Apprise API ships no authentication of its own, so unlike a Slack or a Discord webhook URL - which carries its own signature - an Apprise endpoint is only as protected as the network it sits on. If you put yours behind a reverse proxy that requires a token, you can pass it here.

request-headers:
  Authorization: "Bearer YourToken"

Apprise integration example
integrations:
  apprise:
    # Stateful: the target services are stored in Apprise under the "kuvasz" key
    - name: apprise-example
      url: 'http://your-apprise-host:8000/notify/kuvasz'
    # ...routing to a subset of that stored configuration
    - name: apprise-devops
      url: 'http://your-apprise-host:8000/notify/kuvasz'
      tag: 'devops, oncall'
      global: true
    # Stateless: the target services travel in every request
    - name: apprise-stateless
      url: 'http://your-apprise-host:8000/notify'
      target-urls:
        - 'slack://TokenA/TokenB/TokenC'
        - 'tgram://bottoken/ChatID'
    # ... other Apprise integrations

Pushover

Configuration alias: pushover

Pushover delivers push notifications to your phone, tablet and desktop, without you having to run anything yourself.

The notifications carry a title that names the monitor or the maintenance window the event belongs to, and a body that leads with the summary of the event, followed by its details. The severity decides the priority, which is what tells Pushover whether the notification is allowed to break through the quiet hours of the recipient.

Event Priority
A monitor went down, a certificate became invalid 1 (high), or 2 (emergency, if enabled)
Everything else 0 (normal)

Getting your user key and API token

  1. Sign up at pushover.net and copy your User Key from the dashboard. This is your user-key. A group key works just as well, if you want to notify a whole team.
  2. Create a new application at the bottom of the dashboard, under Your Applications. The token you get there is your api-token.

API token

4.3.0 string api-token

The API token of the Pushover application that sends the notifications. You get it when you register a new application on the Pushover dashboard.

User key

4.3.0 string user-key

The user key or group key the notifications are delivered to. Your user key is on your Pushover dashboard; a group key comes from a delivery group, and lets you notify several people with one integration.

Device

4.3.0 empty string device

Limits the delivery to specific devices instead of every device of the user. Separate the device names with commas, exactly as Pushover expects them:

device: 'iphone,desk'

Leave it empty to reach every device, which is what you usually want for an uptime alert.

Sound

4.3.0 empty string sound

The notification sound to play, instead of the recipient's default. The list of the available names is in the Pushover API documentation - siren, alien and persistent are the ones that stand out from an ordinary notification.

Emergency priority

4.3.0 false boolean emergency-enabled

Sends the critical events with emergency priority (2), which makes Pushover repeat the notification until someone acknowledges it. Only the events that would otherwise get the high priority are escalated: a monitor going down, and a certificate becoming invalid. Recoveries, expiry warnings, DNS drift, maintenance windows and the test notification are never escalated.

Kuvasz calls the alert off when the monitor recovers

You don't have to acknowledge an emergency notification just because the service came back on its own. When the monitor recovers - or the certificate becomes valid again - Kuvasz cancels the outstanding notification for you, and the repeating stops.

It does that without storing anything: the notification is tagged with an identifier derived from the monitor (kuvasz_uptime_<monitor id> and kuvasz_ssl_<monitor id>), and the recovery cancels that same tag.

Two consequences are worth knowing about:

  • If you exclude the recovery event of a monitor with excluded-events, there is nothing left to trigger the cancellation, so the notification keeps repeating until it expires.

Emergency retry seconds

4.3.0 60 integer emergency-retry-seconds

How often an emergency notification is repeated, in seconds. Only has an effect when emergency-enabled is turned on. Pushover requires at least 30 seconds here, so Kuvasz refuses to start with anything lower.

Emergency expire seconds

4.3.0 1800 integer emergency-expire-seconds

How long Pushover keeps repeating an unacknowledged emergency notification, in seconds. Only has an effect when emergency-enabled is turned on. The maximum is 10800 seconds (3 hours), and Kuvasz refuses to start above it. Pushover stops after 50 attempts regardless of this value.


Pushover integration example
integrations:
  pushover:
    # The simplest setup: every device of the user, default sound
    - name: pushover-example
      api-token: 'YourApplicationToken'
      user-key: 'YourUserKey'
      global: true
    # An on-call setup that nags until someone acknowledges it, but calls itself off on recovery
    - name: pushover-oncall
      api-token: 'YourApplicationToken'
      user-key: 'YourGroupKey'
      sound: 'siren'
      emergency-enabled: true
      emergency-retry-seconds: 60
      emergency-expire-seconds: 1800
    # ... other Pushover integrations

Email

Configuration alias: email

The email integration allows you to send notifications via email. You can have multiple email integrations, each with its own sender and recipient addresses.

Warning

To make the email integration work, it's not enough to just configure the integration itself, you also need to set up the SMTP configuration. You can have multiple email integrations, but they will all use the same SMTP configuration.

For more information, see the SMTP configuration section of the documentation.

From address

2.0.0 string from-address

The email address from which the notifications will be sent. This is the address that will appear in the "From" field of the email.

To address

2.0.0 string to-address

The email address to which the notifications will be sent.


Email integration example
integrations:
  email:
    - name: email_implicitly_enabled
      from-address: noreply@kuvasz-uptime.dev
      to-address: your@email.address
    - name: email_disabled
      from-address: noreply@other-sender.com
      to-address: other-recipient@blabla.com
      enabled: false
    # ... other email integrations

PagerDuty

Configuration alias: pagerduty

The PagerDuty integration allows you to trigger incidents in PagerDuty when a monitor goes down, and to automatically resolve them when the monitor comes back up.

Things to do in PagerDuty first

  1. From the Configuration menu, select Services.
  2. There are two ways to add an integration to a service:
  3. If you are adding your integration to an existing service: Click the name of the service you want to add the integration to. Then, select the Integrations tab and click the New Integration button.
  4. If you are creating a new service for your integration: Please read our documentation in section Configuring Services and Integrations and follow the steps outlined in the Create a New Service section, selecting "Kuvasz" as the Integration Type in step 4. Continue with the "In Kuvasz" section (below) once you have finished these steps.
  5. Enter an Integration Name in the format monitoring-tool-service-name (e.g. Kuvasz-Your-Service) and select "Kuvasz" from the Integration Type menu.
  6. Click the Add Integration button to save your new integration. You will be redirected to the Integrations tab for your service.
  7. An Integration Key will be generated on this screen. Keep this key saved in a safe place, as it will be used when you configure the integration with Kuvasz in the next section. Copy PD key

Integration Key

2.0.0 string integration-key

The integration key of the PagerDuty service where the incidents will be created. You can find this key in your PagerDuty service settings.


PagerDuty integration example
integrations:
  pagerduty:
    - name: pd_global
      integration-key: YourOwnIntegrationKey
      global: true
    - name: pd_disabled
      integration-key: YourOtherIntegrationKey
      enabled: false
    # ... other PagerDuty integrations

Telegram

Configuration alias: telegram

The Telegram integration allows you to send notifications to a Telegram chat via a bot.

Getting your bot token and chat ID

  1. Create a new bot by talking to the BotFather on Telegram.
  2. After creating the bot, you will receive a bot token, this will be your api-token.
  3. Invite your bot to the chat where you want to receive notifications, or create a new group and add the bot to it.
  4. To get your chat ID, send a message to your desired chat and then visit https://api.telegram.org/bot<YourApiToken>/getUpdates in your browser, where <YourApiToken> is the token you received from the BotFather. Look for something like this in the response, this will be your chat-id:

    {
       // ... other fields ...
       "sender_chat": {
       "id": -343243243111,
       "title": "kuvasz uptime events",
       "type": "channel"
       },
       // ... other fields ...
    }
    

API token

2.0.0 string api-token

The API token of the Telegram bot that will send the notifications. You can get this token from the BotFather when you create your bot.

Chat ID

2.0.0 string chat-id

The chat ID of the Telegram chat where the notifications will be sent. You can get this ID by following the steps outlined in the Getting your bot token and chat ID section.


Telegram integration example
integrations:
  telegram:
    - name: telegram_global
      api-token: 'YourToken'
      chat-id: '-1232642423121'
      global: true
    - name: telegram_disabled
      api-token: 'YourOtherToken'
      chat-id: '-1232546142423121'
      enabled: false
    # ... other Telegram integrations

Webhooks

Configuration alias: webhook

The Webhook integration allows you to send notifications to any endpoint that can receive HTTP requests. You can use it to integrate with 3rd party services that are not natively supported by Kuvasz, or to implement custom notification logic within your own infrastructure.

Warning

Make sure that your target endpoint handles the configured HTTP method and is able to process the payload sent by Kuvasz. Otherwise, you might end up with failed notifications and missed alerts.

The generic webhook message (if you don't use a custom template) has the following structure:

{
  "monitorId": "234 (6)",
  "monitorUrn": "http:GitHub API (1)",
  "monitorName": "GitHub API (2)",
  "monitorDetailsUrl": "/http-monitors/1 (7)",
  "timestamp": "1777661064488 (3)", 
  "type": "HTTP_DOWN (4)",
  "eventDetails": "Your monitor \"GitHub API\" (https://api.github.com) is DOWN. Reason: Connect Error: Connection refused: api.github.com (5)"
}
  1. monitorUrn: A unique identifier of a monitor, formatted as 'type:name'.
  2. monitorName: The name of the monitor, which must be unique.
  3. timestamp: The timestamp of the event that triggered the webhook, in milliseconds since the Unix epoch.
  4. type: The type of the event that triggered the webhook, which can be one of the following values: HTTP_UP, HTTP_DOWN, PUSH_UP, PUSH_DOWN, ICMP_UP, ICMP_DOWN, TCP_UP, TCP_DOWN, DNS_UP, DNS_DOWN, DNS_RECORDS_CHANGED, SSL_VALID, SSL_INVALID, SSL_WILL_EXPIRE.
  5. eventDetails: A human-readable message with more details about the event.
  6. monitorId: A unique, numeric ID of a monitor.
  7. monitorDetailsUrl: The relative URL to the monitor details page in the Kuvasz web interface.
GenericWebhookMessage:
  required:
  - monitorId
  - monitorUrn
  - monitorName
  - monitorDetailsUrl
  - timestamp
  - type
  - eventDetails
  type: object
  properties:
    monitorId:
      type: integer
      format: int64
    monitorUrn:
      type: string
    monitorName:
      type: string
    monitorDetailsUrl:
      type: string
    timestamp:
      type: integer
      format: int64
    type:
      type: string
      enum:
        - HTTP_UP
        - HTTP_DOWN
        - PUSH_UP
        - PUSH_DOWN
        - ICMP_UP
        - ICMP_DOWN
        - TCP_UP
        - TCP_DOWN
        - DNS_UP
        - DNS_DOWN
        - DNS_RECORDS_CHANGED
        - SSL_VALID
        - SSL_INVALID
        - SSL_WILL_EXPIRE
    eventDetails:
      type: string

Header & payload templates

Kuvasz uses the Pebble templating engine, so you can use all the features provided by Pebble in your templates, including conditionals, loops, filters, and more. Pebble is very similar to Twig (PHP) and Jinja (Python) in order to make it easy to use and understand, even if you didn't work with a JVM templating engine before.

For further information on how to use Pebble templates, please refer to the official documentation.

Strict variables

Keep in mind that template variables are handled in a strict way, which means that if you try to use a variable that is not available in the context, or if you make a typo in the variable name, the template rendering will fail and the request won't be sent. So make sure to double-check your templates and test them before using them in production.

Available context variables

The context variables are available in an object named ctx, and the structure is the same as the generic webhook message described above, so for example you can use {{ctx.monitorName}} to include the name of the monitor in your payload, or {{ctx.type}} to include the type of the event that triggered the webhook.

Having conflicting characters in your hard-coded headers?

In case your template would contain some characters that interfere with Pebble's own syntax, you can use the {% verbatim %} tag to bypass parsing them, like this:

request-headers:
  This-Should-Work-Too: "{% verbatim %}{%{% endverbatim %}" # Rendered as "{%"

URL

3.8.0 string url

The URL of the endpoint where the notifications will be sent. This can be any URL that can receive HTTP requests, for example, an API endpoint of a 3rd party service, or an endpoint of your own backend.

Starting from version 3.11.0, you can also use templates in the URL, which allows you to construct dynamic endpoint URLs based on the context of the event that triggered the webhook. For example, you can route notifications to different paths based on the event type:

url: "https://my-backend.example.com/webhooks/{{ ctx.type }}/{{ ctx.monitorName }}"

Request headers

3.8.0 map request-headers

Optional HTTP headers that will be included in the requests sent to the target URL. This can be useful, for example, to include an Authorization header if the target endpoint requires authentication. The only header that is always included in the requests is the Content-Type header, which is set to application/json by default, but you can override it with your own value if needed.

Starting from version 3.9.0, you can also use templates in the header values, which allows you to include dynamic information in the headers based on the context of the event that triggered the webhook. For example, you can include the monitor name or the event type in a custom header by using a template like this:

request-headers:
  X-Monitor-Name: "{{ctx.monitorName}}"
  X-Event-Type: "{{ctx.type}}"

HTTP method

3.11.0 POST string http-method

The HTTP method used when sending requests to the target URL. The valid options are POST, PUT, PATCH, and GET. Defaults to POST if not specified, which is the correct choice for most services. Use PUT or PATCH when your target endpoint explicitly requires it. Use GET for endpoints that only accept GET requests — note that in this case the payload will not be sent as a request body.

integrations:
  webhook:
    - name: matrix
      url: 'http://your-matrix-webhook-host:4785/!roomid:your-homeserver/your-shared-token'
      http-method: PUT

Payload template

3.8.0 string payload-template

You can customize the payload of the requests sent to the target URL by providing a payload template. This template can include any of the available context variables, which will be replaced with their actual values when the request is sent. This allows you to create custom payloads that fit the requirements of your target endpoint.


Webhook integration example
webhook:
  - name: webhook_templated
    url: https://any-other-http.service/webhooks
    http-method: POST
    excluded-events:
      - PUSH_UP
      - HTTP_UP
      - SSL_WILL_EXPIRE
    request-headers:
      Accept: '*/*'
      Authorization: Bearer your-webhook-secret-token
      X-Custom-Header: custom-value
    payload-template: |
      {
        "monitorName": "{{ctx.monitorName}}",
        "type": "{{ctx.type}}"
      }
  - name: webhook_put
    url: https://any-other-http.service/resource/123
    http-method: PUT
    payload-template: |
      {
        "monitorName": "{{ctx.monitorName}}",
        "type": "{{ctx.type}}"
      }
  # ... other Webhook integrations

Webhook examples

Here are some examples of webhook configurations that you can use for different 3rd party services as a starting point. Kuvasz is using Pebble as a templating engine under the hood, for further information on how to use Pebble templates, please refer to the official documentation.

Sharing is caring!

Did you make a cool webhook configuration that you would like to share with the community? Feel free to open a PR on GitHub with your example, and we will add it to the documentation!

Signal (via signal-cli-rest-api)

This example sends notifications to a Signal chat using signal-cli-rest-api — a self-hosted, dockerized REST wrapper around signal-cli. You need a dedicated Signal number registered with the container (see the project's README for setup).

integrations:
  webhook:
    - name: signal
      url: 'http://your-signal-api-host:8080/v2/send'
      payload-template: |
        {
          "message":    "{{ ctx.eventDetails | escape(strategy="js") }}",
          "number":     "+15550001234",
          "recipients": ["+15550005678"]
        }

Twilio — SMS

This example sends an SMS via the Twilio Messaging API.

Content type

Twilio's Messaging API requires application/x-www-form-urlencoded payloads, not JSON. The example below overrides the default Content-Type header accordingly, and uses escape(strategy="url_param") to URL-encode the dynamic message body.

Twilio setup:

  1. Log in to the Twilio Console.
  2. On the dashboard, note your Account SID and Auth Token.
  3. Make sure you have a Twilio phone number capable of sending SMS. You can get one under Phone Numbers → Manage → Buy a number.
  4. Compute your Base64-encoded credentials by running the following command, then copy the output:

    echo -n "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:your_auth_token" | base64
    
Kuvasz configuration
integrations:
  webhook:
    - name: twilio-sms
      url: 'https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/Messages.json'
      request-headers:
        Content-Type: "application/x-www-form-urlencoded"
        Authorization: "Basic <your-base64-encoded-credentials>"
      payload-template: |
        From=%2B15551234567&To=%2B15550005678&Body={{ ctx.eventDetails | escape(strategy="url_param") }}

Replace %2B15551234567 with your Twilio number and %2B15550005678 with the recipient number — both with the leading + pre-encoded as %2B.

ntfy

This example sends notifications to an ntfy topic — a lightweight, self-hostable push notification service. ntfy supports both the hosted ntfy.sh server and self-hosted instances.

Kuvasz configuration
integrations:
  webhook:
    - name: ntfy_test
      url: https://ntfy.sh
      payload-template: |
        {
          "topic": "kuvasz_uptime_test",
          "message": "{{ ctx.eventDetails | escape(strategy="js") }}",
          "title": "Kuvasz Uptime Alert",
          "tags": [ "rotating_light" ],
          "priority": 4,
          "attach": null,
          "filename": null,
          "click": null,
          "actions": [ { "action": "view", "label": "View details", "url": "https://demo.kuvasz-uptime.dev{{ctx.monitorDetailsUrl}}" } ]
        }

Ntfy test notification

Pushover

Pushover has a first-class integration since version 4.3.0...

... so there is no need to hand-craft a webhook payload for it anymore. See the Pushover section above: it sends a proper title, body and priority, it can escalate an outage to the emergency priority, and it calls that alert off by itself once the monitor recovers.

Home Assistant — webhook automation

This example triggers a Home Assistant webhook automation when a monitor event occurs, letting you react to uptime events natively within Home Assistant — for example, to send a mobile notification, toggle a switch, or run a script.

Tip

If you want to read monitor data from Kuvasz instead of receiving push events, see the official Home Assistant integration.

Home Assistant setup:

  1. Go to Settings → Automations & Scenes → Automations and click + Create automation.
  2. Select "Create new automation" and add a Webhook trigger. Copy the generated, secure webhook ID and make sure POST is listed under Allowed HTTP methods. The resulting webhook URL is something like:
    http://your-ha-instance:8123/api/webhook/yourVerySecretWebhookId
  3. Add any actions you like, and save the automation.

The fields from the Kuvasz payload are available in Home Assistant automation templates via trigger.json, for example:

Kuvasz field Home Assistant template
type {{ trigger.json.type }}
monitorName {{ trigger.json.monitorName }}
message {{ trigger.json.message }}
Kuvasz configuration
integrations:
  webhook:
    - name: home-assistant
      url: 'http://your-ha-instance:8123/api/webhook/yourVerySecretWebhookId'
      payload-template: |
        {
          "type":        "{{ ctx.type }}",
          "monitorName": "{{ ctx.monitorName | escape(strategy="js") }}",
          "message":     "{{ ctx.eventDetails | escape(strategy="js") }}"
        }

Webhook ID is the secret

Home Assistant webhook triggers don't require an Authorization header — the webhook ID itself acts as the shared secret. Keep it reasonably hard to guess and, where possible, restrict external access to the endpoint via your firewall or reverse proxy.

Google Chat

This example posts a message to a Google Chat space via an incoming webhook.

Google Chat setup:

  1. Open the target space in Google Chat and click the space name at the top.
  2. Go to Integrations → Webhooks → Add webhook.
  3. Give the webhook a name (e.g. Kuvasz) and click Save. Copy the generated Webhook URL.
Kuvasz configuration — plain text
integrations:
  webhook:
    - name: google-chat
      url: 'https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN'
      payload-template: |
        {
          "text": "{{ ctx.eventDetails | escape(strategy="js") }}"
        }

Apprise API

Apprise has a first-class integration since version 4.3.0...

... so there is no need to hand-craft a webhook payload for it anymore. See the Apprise section above: it sends a proper title, body and severity, and it supports both the stateful and the stateless mode.

Mattermost

This example posts a message to a Mattermost channel via an incoming webhook. Mattermost's webhook format is compatible with Slack's, so the payload is identical.

Mattermost setup:

  1. In Mattermost, go to Main menu → Integrations → Incoming webhooks → Add incoming webhook.
  2. Select the target channel, give the webhook a display name, and click Save.
  3. Copy the generated webhook URL.

Incoming webhooks may be disabled

If you don't see the Integrations menu, ask your Mattermost system administrator to enable incoming webhooks.

Kuvasz configuration
integrations:
  webhook:
    - name: mattermost
      url: 'https://your-mattermost-instance/hooks/your_webhook_token'
      payload-template: |
        {
          "text": "{{ ctx.eventDetails | escape(strategy="js") }}"
        }

You can also target a different channel than the one set during webhook creation, set a custom username, or override the icon — all via standard Mattermost payload fields:

Kuvasz configuration - with overrides
integrations:
  webhook:
    - name: mattermost-custom
      url: 'https://your-mattermost-instance/hooks/your_webhook_token'
      payload-template: |
        {
          "channel":   "town-square",
          "username":  "Kuvasz",
          "icon_url":  "https://kuvasz-uptime.dev/images/kuvasz-logo.webp",
          "text":      "{{ ctx.eventDetails | escape(strategy="js") }}"
        }

Rocket.Chat

This example posts a message to a Rocket.Chat channel via an incoming webhook. Like Mattermost, Rocket.Chat uses a Slack-compatible webhook format.

Rocket.Chat setup:

  1. Go to Administration → Integrations → New and select Incoming webhook.
  2. Set Enabled to true, choose the target channel, and give the integration a name.
  3. Click Save and copy the generated webhook URL.
Kuvasz configuration
integrations:
  webhook:
    - name: rocketchat
      url: 'https://your-rocketchat-instance/hooks/your_token/your_secret'
      payload-template: |
        {
          "text": "{{ ctx.eventDetails | escape(strategy="js") }}"
        }

Rocket.Chat supports the same optional fields as Mattermost (channel, username, icon_url, icon_emoji) so you can use the same overrides shown in the Mattermost example above.

Testing integrations

It's vital to ensure that your integrations are correctly set up to receive notifications. You can test your integrations (even the disabled ones) directly either:

  • From the web interface by navigating to the Integrations page and clicking the button next to the integration you want to test. In this case you'll see the result in a visual way, at the same place where you initiated the test.
  • Via the API by sending a POST request to /api/v2/integrations/{integrationId}/test, where {integrationId} is the ID of the integration you want to test (for example, slack:your-desired-name). In this case the payload of the response should be straightforward to understand whether the test was successful or not.

Testing PagerDuty integrations

Please note that when testing PagerDuty integrations, a real incident will be created in your account, which will be immediately resolved by Kuvasz.

Testing webhook integrations

When you test a Webhook integration, a separate test message will be generated and sent for every event type that the integration watches, so for example if you have an integration that watches both HTTP_UP and HTTP_DOWN events, you will receive two separate messages in your target endpoint when you test the integration: one for the UP event and one for the DOWN event. The "down" events will be always fired first to simulate a real downtime scenario, and the "up" events will be fired immediately after to simulate the recovery of the monitor.

Integrations list

Do you miss an integration?

If you miss an integration, please open an issue, or consider contributing it yourself! We are always open to new integrations and would love to see your contribution.