Skip to content

DumbMonit notifications

This content is not available in your language yet.

This guide explains how to receive DumbMonit alerts on the service of your choice. It requires no programming skills: each section says where to find the address or token to copy, and what to type into the form.



A channel is a destination: a Discord channel, a phone number, a mailbox. You create as many as you want, and your alert rules choose which ones to notify.

Three principles apply to every channel:

  1. Alerts are grouped. One message per monitor and per cycle, even if five disks fill up at the same time. Without this, you would mute notifications within a week.
  2. A broken channel never blocks another one. The failure is recorded in the channel’s “last error” column, and delivery continues to the others.
  3. A service that does not answer is abandoned after 15 seconds. A notification that arrives a minute late is no longer useful, and the monitoring loop must not wait behind an unreachable server.

  1. Open Settings → Notifications → Add channel (/settings/notifications).
  2. Give it a meaningful name (“Discord — family”, “SMS — on-call”). This is the name you will pick later in your alert rules.
  3. Choose the channel type, then fill in the fields described below.
  4. Save, then click Send test.

The test message takes exactly the same path as a real alert: same request, same token, same formatting. If it arrives, the channel works. If it fails, the error message names the setting to fix.

A token is never shown again. Once saved, it is encrypted in the database and the interface only says “configured”. To edit a channel without retyping its token, simply leave the field empty.


Every channel has two groups of fields.

SettingsSecrets
Contentserver address, channel name, topictokens, passwords, webhook URLs
Storageplain textencrypted
Read back by the interfaceyesnever

The interface refuses to save a sensitive field among the settings, and tells you so. This is not a formality: settings are returned as-is by the API, so a token stored there would be published every time the page is opened.

The tables in the Supported channels section say, for each channel, what goes where.


By default DumbMonit refuses any server whose certificate it cannot verify. For a self-hosted service served with a self-signed certificate or one from a private authority, the channels for Matrix, Mattermost, Rocket.Chat, Zulip, ntfy, Gotify, Bark, Apprise, Home Assistant, Signal and the custom webhook have an Accept an unverifiable certificate setting (insecure_tls, a boolean, off by default).

Turning it on keeps the connection encrypted but stops checking the identity of the server, so use it only for a server you control, on a network you trust. When a certificate is the reason for a failure, the error shown for the channel names it (for example “invalid peer certificate: UnknownIssuer”).


Acknowledge or snooze from the notification

Section titled “Acknowledge or snooze from the notification”

When a public URL is set (Settings → Notifications → Notification policy, or DUMBMONIT_PUBLIC_URL), every alert message carries three actions:

  • Dismiss: “got it”. The alert leaves the active list and nothing more is sent for it, not even its resolution, until the condition clears; if it comes back later, it alerts again. It comes first, so it is the one kept where only two buttons fit (Web Push in most browsers).
  • Acknowledge: no more reminders until the alert resolves. The resolution is still announced.
  • Snooze 1 h: no reminders for one hour; they resume afterwards if the alert is still active. A snooze never shortens a longer acknowledgement.

How they show up depends on the channel:

ChannelShown as
ntfy, Telegram, Web PushButtons under the notification
Discord, Slack, email and every other channelLinks at the end of the message
Custom webhookLinks in {{message}}, and the {{dismiss_url}} / {{ack_url}} / {{snooze_url}} variables
PagerDuty, Opsgenie, Grafana OnCall, SIGNL4Nothing: acknowledge in the service itself
Jira, GLPI, Zammad, GitHub Issues, GitLab IssuesNothing: the acknowledgement is added to the ticket as a comment
Vonage, Telnyx, ASPSMS (SMS)Nothing: a signed link would cost several SMS segments

Telegram only accepts buttons pointing to an https address with a domain name; with an IP address or a plain http URL, the actions stay as links in the text. Web Push only shows the buttons on devices of operators and admins: a viewer sees the alert, not a way to silence it.

A link opens a short confirmation page in DumbMonit: nothing happens until you press the button. Mail clients, chat apps and antivirus scanners open links to build previews; they only load the page. No sign-in is needed: the link itself is the permission, and only for that gesture, on the alerts of that message (that firing: if an alert resolves and fires again, the old link no longer covers it), once, for 24 hours. The action is recorded in the audit log, and the alert shows “acknowledged by via notification link” (or “dismissed by via notification link”).

Security, in short: each link is signed with a key derived from the instance secret (changing the secret invalidates every link), carries no session, and travels after the # of the address, which browsers never send to a server, so it appears in no access or proxy log. A forged, altered or expired link gets the same answer as any other invalid link, and repeated attempts from one address are slowed down.

Turn Acknowledge and snooze from notifications off in the notification policy to stop adding them; this also invalidates the links already sent. Clearing the public URL has the same effect.


The webhook channel is DumbMonit’s escape hatch. You describe the whole HTTP request — method, address, headers, content type and body —, which lets you plug in almost any service, including an internal API DumbMonit will never know about.

Without any particular configuration, it already sends a structured JSON payload that a script can use:

{
"source": "dumbmonit",
"target": "nas",
"rule": "Disk full",
"severity": "warning",
"status": "firing",
"title": "nas — Disk full",
"text": "⚠️ Warning · Disk full — /data — 95 % (threshold > 90 %)",
"value": 95.0,
"threshold": 90.0,
"unit": "%",
"fingerprint": "nas/disk-full",
"count": 1,
"at": "2026-09-01T14:12:05+00:00",
"link": "https://dumbmonit.home/targets/42"
}

link points to the monitor page, built on the public_url of the notification policy (or DUMBMONIT_PUBLIC_URL), or on the channel’s base_url. A message about several monitors, and the test message, link to the instance itself. Without any public URL, link is null.

SettingRequiredDefaultRole
urlyes (here or as a secret)—Address to call. May contain variables.
methodnoPOSTPOST, PUT or GET.
content_typenojsonjson, form or text. Also determines how variables are escaped.
body_templateno—Body template. When absent, the payload above is sent.
base_urlno—Public address of your DumbMonit, so that {{link}} gives a clickable link.
usernameno—Username for HTTP “Basic” authentication. Requires the password secret.
SecretRole
urlUse it instead of the url setting if the address already contains a token.
tokenSent as an Authorization: Bearer … header, unless your template uses {{token}}.
passwordPassword for “Basic” authentication.
headersExtra headers, as a JSON object {"X-Api-Key": "value"}. Stored encrypted like the token and never shown again, so API keys and Authorization headers belong here.

headers is a secret. Channels saved by 0.1.0-alpha.6 or earlier, which kept them in the settings, have them moved to the encrypted secrets at the first start, and the API no longer returns them. Like every secret, they are kept when you edit the channel without typing them again; sending secrets replaces the whole set.

DumbMonit follows a redirect only to the same host (or from http to https on that host): a channel’s headers and token never go anywhere but the address you entered.

A variable is written between double braces: {{title}}. Spaces around the name are tolerated ({{ title }}). Single braces in a JSON body stay literal, so you can write your JSON normally.

VariableWhat it containsExample
{{title}}Full message titlenas — Disk full
{{message}}Plain-text body, one line per alert⚠️ Warning · Disk full — /data — 95 % (threshold > 90 %)
{{message_markdown}}The same body in Markdown**nas — Disk full**\n• ⚠️ …
{{rule}}Name of the alert ruleDisk full
{{target}}Name of the monitornas
{{target_id}}Numeric identifier of the monitor42
{{severity}}Technical severityinfo, warning or critical
{{severity_fr}}Severity as a readable wordinformation, avertissement, critique
{{status}}Technical statusfiring or resolved
{{status_fr}}Status as a readable worden cours or résolu
{{value}}Measured value, unit included95 %
{{value_raw}}Bare value, usable as a JSON number95
{{threshold}}Crossed threshold, unit included90 %
{{threshold_raw}}Bare threshold, usable as a JSON number90
{{unit}}Unit of the value%
{{operator}}Threshold comparison>
{{count}}Number of alerts grouped in this message3
{{fingerprint}}Stable identifier of the alertnas/disk-full
{{timestamp}}ISO 8601 timestamp2026-09-01T14:12:05+00:00
{{timestamp_unix}}Timestamp in seconds since 19701788358325
{{date}}Readable timestamp, in UTC2026-09-01 14:12 UTC
{{priority}}Priority from 1 (low) to 5 (high)4
{{color}}Accent colour, without hashD98A00
{{color_hex}}Accent colour, with hash#D98A00
{{emoji}}Status pictogram🔴, ⚠️, ℹ️ or ✅
{{link}}Link to the monitor in DumbMonithttps://dumbmonit.home/targets/42
{{source}}Always dumbmonitdumbmonit
{{token}}The channel’s token secret(your token)
{{ack_url}}Signed link that acknowledges the alert until it resolves, empty if action links are offhttps://dumbmonit.home/alert-action#…
{{snooze_url}}Signed link that snoozes the alert for one hour, empty if action links are offhttps://dumbmonit.home/alert-action#…
{{dismiss_url}}Signed link that dismisses the alert (hidden and silent until it resolves), empty if action links are offhttps://dumbmonit.home/alert-action#…

Two useful remarks:

  • Some variables can be empty. An availability alert (“host unreachable”) has neither a value nor a threshold: {{value}} and {{value_raw}} then render an empty string, never null or NaN. If you place them as a JSON number, handle that case — or use "{{value}}" between quotes.
  • {{link}} stays empty until you fill in base_url. A wrong link would waste more time than an alert without one.

You never need to escape anything yourself. Depending on the chosen content_type, DumbMonit automatically protects substituted values: quotes and line breaks escaped in JSON, percent-encoding in a form, no transformation in plain text. A rule named "System" disk full will not break your JSON template.

A home-grown application exposes POST /incidents and expects a token in a custom header.

Settings

{
"url": "https://api.internal.example.org/incidents",
"method": "POST",
"content_type": "json",
"base_url": "https://dumbmonit.home",
"body_template": "{\"title\": \"{{title}}\", \"device\": \"{{target}}\", \"severity\": \"{{severity}}\", \"state\": \"{{status}}\", \"value\": {{value_raw}}, \"threshold\": {{threshold_raw}}, \"detail\": \"{{message}}\", \"link\": \"{{link}}\", \"seen_at\": \"{{timestamp}}\"}"
}

Secrets

{
"token": "your-application-token",
"headers": "{\"X-Application\": \"dumbmonit\"}"
}

The token is sent automatically as an Authorization: Bearer … header. Here is what the application receives:

{
"title": "nas — Disk full",
"device": "nas",
"severity": "warning",
"state": "firing",
"value": 95,
"threshold": 90,
"detail": "⚠️ Warning · Disk full — /data — 95 % (threshold > 90 %)",
"link": "https://dumbmonit.home/targets/42",
"seen_at": "2026-09-01T14:12:05+00:00"
}

Example 2 — a service that expects a form

Section titled “Example 2 — a service that expects a form”

Many SMS gateways and older APIs expect application/x-www-form-urlencoded rather than JSON, with the token in the body.

Settings

{
"url": "https://gateway.example.org/api/send",
"method": "POST",
"content_type": "form",
"body_template": "key={{token}}&recipient=0612345678&subject={{title}}&text={{emoji}} {{message}}&priority={{priority}}"
}

Secrets

{ "token": "gateway-key" }

Since the template already uses {{token}}, DumbMonit does not add an Authorization header: some services reject a request that carries two authentications. Values are encoded automatically, spaces becoming + and accented characters their percent-encoded equivalent.

Example 3 — a plain-text SMS through a carrier

Section titled “Example 3 — a plain-text SMS through a carrier”

Some services, such as a carrier’s SMS API or a home-made automation, want a single line of text.

Settings

{
"url": "https://automation.home/alert",
"method": "POST",
"content_type": "text",
"body_template": "{{emoji}} {{severity}} on {{target}}: {{rule}} ({{value}}, threshold {{operator}} {{threshold}}) — {{date}}"
}

The message sent, without any escaping:

⚠️ warning on nas: Disk full (95 %, threshold > 90 %) — 01/09/2026 14:12 UTC

Example 4 — a GET request without a body

Section titled “Example 4 — a GET request without a body”

When the service only accepts URL parameters, put the variables in url and choose the GET method. A GET request has no body: body_template is then rejected, so that nobody believes it does something.

Settings

{
"url": "https://sms.example.org/send?user=noe&text={{title}} — {{value}}",
"method": "GET"
}

Secrets

{ "token": "api-key" }

Only the substituted values are encoded; the rest of the address is copied as-is. The request actually sent looks like:

GET https://sms.example.org/send?user=noe&text=nas%20%E2%80%94%20Disk%20full%20%E2%80%94%2095%20%25

A faulty template is rejected when saved, while you are looking at the form, not on the night the incident happens.

What you writeWhat happens
{{severite}}Rejected: unknown variable “severite”, followed by the list of valid names. The correct name is severity.
{"t": "{{title"}Rejected: “unclosed braces”. The }} is missing.
{{}} or {{ }}Rejected: a variable without a name means nothing.
{"a": {"b": 1}}Accepted. Single braces are literal: write your JSON normally.
{{token}} without a token secretRejected: the template asks for a token the channel does not have.
method: GET with body_templateRejected, with the alternative: put the variables in url.
method: DELETERejected: only POST, PUT and GET are accepted.

In Discord: Channel settings → Integrations → Webhooks → New webhook, then Copy webhook URL. This URL contains the token: it goes into the secrets.

  • Secrets — webhook_url

On https://api.slack.com/apps, create an app, enable Incoming Webhooks, then Add New Webhook to Workspace and pick the channel. Copy the https://hooks.slack.com/services/… URL.

  • Secrets — webhook_url

You need two things: the bot token (secret) and the chat ID (chat_id) where it must write. The first takes a minute to get; the second depends on where you want to receive the alerts.

  1. In Telegram, search for @BotFather and click Start.

  2. Send /newbot, then answer the questions (a name, then a username that must end with bot).

  3. BotFather ends with a message like this:

    Done! Congratulations on your new bot. You will find it at t.me/my_homelab_bot.
    Use this token to access the HTTP API:
    63xxxxxx71:AAFoxxxxn0hwA-2TVSxxxNf4c

    The line 63xxxxxx71:AAFoxxxxn0hwA-2TVSxxxNf4c is the bot token. Do not share it: it gives full control of the bot.

In the examples below, replace <TOKEN> with this token. Note the bot prefix glued in front of it in URLs: https://api.telegram.org/bot<TOKEN>/….

Private chat (the bot writes to you directly)

  1. Open your bot (t.me/my_homelab_bot) and click Start, or send it any message. Without this, it will never be able to write to you.

  2. Open in a browser: https://api.telegram.org/bot<TOKEN>/getUpdates

  3. You get a JSON document; look for "chat":

    {"ok":true,"result":[{"update_id":83xxxxx35,
    "message":{"message_id":2643,"from":{…},
    "chat":{"id":21xxxxx38,"first_name":"…","type":"private"},
    "date":1703062972,"text":"/start"}}]}

    The chat_id is the value of chat.id: here 21xxxxx38 (a positive number).

    If result is empty ("result":[]), send the bot another message and reload the page.

Channel

  1. Add the bot as an administrator of the channel (Manage channel → Administrators → Add).

  2. Post a message in the channel.

  3. Open https://api.telegram.org/bot<TOKEN>/getUpdates: the response contains a channel_post block with "chat":{"id":-1001xxxxxx062,"type":"channel"}.

    The chat_id is that negative number, -100 included: -1001xxxxxx062.

Group

The easiest way goes through the desktop app:

  1. Add the bot to the group.
  2. Send a message in the group, right-click it → Copy message link. You get https://t.me/c/194xxxx987/13 (or https://t.me/c/194xxxx987/11/13 if the group has topics).
  3. The number right after /c/ is the group’s internal identifier: 194xxxx987. The chat_id to enter is that number prefixed with -100: -100194xxxx987.

Without the desktop app, the getUpdates method above works too: message.chat.id is directly the right number (already negative). If the bot does not see the group’s messages, ask BotFather for /setprivacy → Disable, then remove the bot from the group and add it again.

Group topic (groups in “Topics” mode)

The chat_id is the group’s. In addition, fill in Group topic (message_thread_id) with the middle number of the copied link: in https://t.me/c/194xxxx987/11/13, the topic is 11. Without this setting, the message lands in the General thread.

Open in the browser:

https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<CHAT_ID>&text=test123

(add &message_thread_id=11 for a topic). If test123 arrives, the token and the chat_id are right: enter them in DumbMonit and click Test.

  • Settings — chat_id (required), message_thread_id (topic, optional), api_base (default https://api.telegram.org, change it only to go through a relay)
  • Secrets — bot_token

“Telegram cannot find this chat” — for a private chat, the bot has never received a message from you: send it /start. For a group or a channel, the -100 prefix is probably missing, or the bot has not been added to it.

“thread not found” — the message_thread_id does not match any topic of the group, or the group is not in “Topics” mode.

Warning: the method has changed. The old “Office 365 connectors” were retired in May 2026; an outlook.office.com/webhook/… URL no longer works.

The current procedure:

  1. In the Teams channel, ⋯ → Workflows.
  2. Choose the “Post to a channel when a webhook request is received” template.
  3. Confirm the steps, then copy the HTTPS POST URL shown at the end.
  • Secrets — webhook_url

DumbMonit sends a wrapped Adaptive Card, the only format these flows display correctly. If you get an error mentioning Power Automate, the URL probably comes from an old connector.

  1. Create an account dedicated to DumbMonit on your homeserver, and invite it to the room. An account that is not a member cannot write.
  2. Get its access token. In Element: Settings → Help & About → Advanced → Access token.
  3. Get the room’s internal identifier — not its display name. In Element: Room settings → Advanced → Internal room ID. It starts with ! (for example !aBcDeF:matrix.org).
  • Settings — server_url (for example https://matrix.org), room_id
  • Secrets — token

Integrations → Incoming Webhooks → Add. Choose the default channel, then copy the URL.

  • Settings — channel (optional, to write somewhere other than the default channel), username (optional, default DumbMonit)
  • Secrets — webhook_url

Administration → Integrations → New integration → Incoming webhook. Choose the room, enable the integration, then copy the Webhook URL.

  • Settings — channel (optional), alias (optional, default DumbMonit)
  • Secrets — webhook_url

In the Google Chat space: space name → Apps & integrations → Webhooks → Add webhook. Copy the URL, which already contains the key and the token.

  • Secrets — webhook_url
  1. Create a bot: Personal settings → Bots → Add a new bot, type “Generic”. Note its email address and its API key.
  2. Subscribe the bot to the target stream, otherwise sending will be refused.
  • Settings — server_url (for example https://your-org.zulipchat.com), email (the bot’s address), stream (the stream name), topic (optional, default DumbMonit)
  • Secrets — api_key

The simplest channel of all: pick a topic name that is hard to guess, then subscribe to it from the ntfy app.

  • Settings — topic, server_url (optional, default https://ntfy.sh)
  • Secrets — token (only if your server requires authentication)

On the public instance, anyone who knows a topic’s name can read it. Pick a long, random name, or host your own server.

In the Gotify interface: Apps → Create Application. Copy the token shown.

  • Settings — server_url (for example https://gotify.home)
  • Secrets — token
  1. On https://pushover.net, your User Key is shown right on the home page.
  2. Then create an application: Create an Application/API Token. You get an application token.
  • Settings — priority (optional, from -2 to 2), sound (optional), retry and expire (only for priority: 2)
  • Secrets — token (application token), user_key (user key)

Without a priority setting, DumbMonit chooses according to severity: -1 for an advisory or a resolution, 0 for a warning, 1 for a critical alert. An advisory therefore does not make the phone ring.

Priority 2 (“emergency”) repeats the notification until it is acknowledged. DumbMonit then adds retry and expire automatically, without which Pushover would reject the message.

On https://www.pushbullet.com/#settings/account, click Create Access Token.

  • Settings — device_iden (optional; without it, all your devices are notified)
  • Secrets — token

Open the Bark app on your iPhone: it shows a URL containing your device key, the long string of characters after the domain name.

  • Settings — server_url (optional, default https://api.day.app), group (optional), level (optional), sound (optional)
  • Secrets — token (the device key)

Without a level setting, DumbMonit chooses: passive for an advisory, active for a warning, timeSensitive for a critical alert. The critical level, which breaks through “Do Not Disturb”, is never chosen automatically — set it explicitly if you want it.

Native notifications on your phones and computers, straight from your own DumbMonit, with no app to install and no third-party account: the browser (installed as an app or not) receives the alerts even with every tab closed.

  1. On each phone or computer, open DumbMonit and go to Settings → Push notifications → Enable on this device, then Send a test. On iPhone and iPad, first add DumbMonit to the Home Screen. The step-by-step guide is in Push notifications (PWA).
  2. Create a Web Push channel here. It has no secret: its recipients are the devices subscribed in step 1.
  • Settings — users (optional; one account per line, empty: every subscribed device of every account), urgency (high by default, normal or low), ttl (seconds the push service keeps the message for a device that is off, default 86400), contact (optional mailto: or https: address given to push services; empty: DUMBMONIT_PUBLIC_URL when it is HTTPS, otherwise the project page)
  • Secrets — none. The server’s VAPID key pair is generated at first start and stored encrypted; the private key never leaves the server.

The notification title is the severity and the monitor (Critical · nas01), the body a short summary; a tap opens the Alerts page. DumbMonit needs outbound HTTPS to the push services (fcm.googleapis.com, *.notify.windows.com, updates.push.services.mozilla.com, *.push.apple.com); messages are end-to-end encrypted, those services cannot read them. A subscription the push service reports as gone (HTTP 404 or 410, for example after the app was removed) is deleted automatically.

Apprise is a gateway: with a single configuration it gives access to dozens of services DumbMonit does not implement itself. Deploy the caronc/apprise container, then choose one of the two modes.

Recommended mode — configuration stored in Apprise. Create a configuration in the Apprise interface, note its key, and put nothing else here.

  • Settings — server_url, config_key

Direct mode — DumbMonit provides the destinations. Apprise URLs often contain a password (mailto://user:password@…): they therefore go into the secrets.

  • Settings — server_url
  • Secrets — urls (one or more Apprise URLs, separated by commas)

Optional common settings: tag (to target only part of a configuration’s destinations) and format (text by default, or markdown).

If the test answers “Apprise has no configuration under this config_key”, the key matches nothing. DumbMonit reports it instead of pretending the message was sent.

  1. In Home Assistant: your profile → Security → Long-lived access tokens → Create token. Copy it, it will not be shown again.
  2. Choose the service to call. By default, DumbMonit creates a persistent notification on the dashboard.
  • Settings — server_url (for example http://homeassistant.local:8123), service (optional, default persistent_notification.create), target (optional), data (optional, object merged into the call)
  • Secrets — token

A few useful services:

serviceEffect
persistent_notification.createBanner in the Home Assistant interface
notify.notifyAll configured notification targets
notify.mobile_app_<device>The mobile app of one specific device
light.turn_onTurns on a light — use data for the entity and the colour

The data setting is merged last: it can therefore override the title or the message DumbMonit prepared.

The only channel that depends on no third-party service.

  • Settings — host, from, to (list of addresses), security (starttls by default, or tls, or none), port (derived from security: 587, 465 or 25), username (optional)
  • Secrets — password

With Gmail, an account password does not work: create an app password in the security settings of your Google account.

Goes through a signal-cli-rest-api instance that you host and where you first register your number.

  • Settings — server_url (for example http://signal.home:8080), number (the registered sender number), recipients (list of numbers or group identifiers), username (optional)
  • Secrets — password (optional, if your instance is protected)

All numbers are written in international format, +33612345678.

On the Twilio console, the home page shows your Account SID and your Auth Token. Then buy a number that can send SMS.

  • Settings — account_sid, from (your Twilio number) or messaging_service_sid, to (list of recipients)
  • Secrets — token (the Auth Token)

The SMS body is truncated at 300 characters: beyond that, Twilio splits it into segments billed separately.

On a trial account, Twilio only sends to numbers you have verified.

Uses the WhatsApp Business Cloud API from Meta. In the Meta developer console, create an app of type Business, add the WhatsApp product and note the Phone number ID under API Setup. Create a permanent token for a system user with the whatsapp_business_messaging permission.

  • Settings — phone_number_id, to (list of numbers in international format)
  • Secrets — token

Meta only allows free text within 24 hours of the recipient’s last message to your business number. Have each recipient write “hello” to the number first. Sending outside that window needs an approved template, which this channel does not use.

A free gateway for notifying yourself, with no Meta account. Add the CallMeBot contact to your phone, send it I allow callmebot to send me messages, and it answers with an API key.

  • Settings — phone (your number in international format)
  • Secrets — api_key

CallMeBot is a third-party service with no guarantee of availability: use the Cloud API for anything critical.

On gateway.threema.ch, create a Basic Gateway ID (eight characters starting with *) and note its secret.

  • Settings — from (the Gateway ID), to (list of eight-character Threema IDs)
  • Secrets — secret

The message is encrypted by the Threema server (basic mode), which is enough for an alert and needs no key pair. Each message consumes a Gateway credit.

On developer.webex.com create a Bot (My Apps → Create a Bot), copy its token, then add the bot to the space. The room ID is returned by the List Rooms API call.

  • Settings — room_id
  • Secrets — token (the bot token)

The message is sent in Markdown.

The API key and secret are on the Vonage API dashboard.

  • Settings — from (a number or alphanumeric name), to (list)
  • Secrets — api_key, api_secret

Create an API key (v2) in the Mission Control Portal and buy a number with SMS enabled.

  • Settings — from (the Telnyx number), to (list, E.164 format with the +)
  • Secrets — api_key
  • Settings — userkey, originator (11 characters at most), to (list)
  • Secrets — password (the API password)

The three SMS channels send at most 300 characters, without emoji, on a single line. They carry no acknowledge/snooze link — a signed link would cost several segments — use a chat channel for that.

In PagerDuty: Services → your service → Integrations → Add integration, and choose Events API v2. Copy the Integration Key.

  • Settings — region (eu if your account is hosted in Europe), source (optional, default dumbmonit)
  • Secrets — token (the Integration Key)

An alert opens an incident; its resolution closes it automatically. Matching is done on the alert’s fingerprint, prefixed with dumbmonit-, so a reminder never opens a second incident.

A key of another type (“Events API v1”, “REST API”) gets a terse refusal. Check that the integration is indeed of type Events API v2.

Teams → your team → Integrations → Add integration → API. Copy the API key.

  • Settings — region (eu for a European account), responders (list of team names, optional), tags (list, optional)
  • Secrets — api_key

As with PagerDuty, a resolution closes the alert, identified by its alias.

Atlassian has set the end of service for Opsgenie on 5 April 2027. This channel stays for existing installations; for a new one, prefer PagerDuty or a custom channel pointing to Jira Service Management.

In Grafana OnCall: Integrations → New integration → Webhook, then copy the HTTP endpoint.

  • Secrets — webhook_url

An alert opens an alert group (state: alerting) and its resolution resolves it (state: ok), matched on a dumbmonit- identifier per device. Acknowledge from OnCall itself.

In SIGNL4, copy the team webhook from Teams → Team settings: it is https://connect.signl4.com/webhook/ followed by your team secret.

  • Secrets — webhook_url

An alert reaches the team’s phones (X-S4-Status: new) and its resolution closes it (resolved), matched on a per-device external ID.

Pages the person on call, then escalates step by step until someone acknowledges. It has a single setting, the escalation policy to run, and no secret. Schedules, contacts and policies are described in On-call; the channel goes through the usual routing (labels, minimum severity, channels chosen per rule).

Automatic tickets (Jira, GLPI, Zammad, GitHub, GitLab)

Section titled “Automatic tickets (Jira, GLPI, Zammad, GitHub, GitLab)”

These five channels do not send a message: they keep one ticket per alert.

  • When an alert opens, the ticket is created: title, description with a link to the device in DumbMonit (set the public address in the notification policy), and a priority taken from the severity.
  • The ticket reference is remembered per alert and per channel, so a reminder or a retry never opens a second one while the first is open.
  • Notable events are added as comments: an escalation, an alert nobody acknowledged in time, a new finding, and an acknowledgement by someone in DumbMonit.
  • When the alert resolves, DumbMonit comments and closes the ticket (transition, status or state configured on the channel).
  • Reopen if the alert returns within (hours) — if the same alert comes back in that delay, the closed ticket is reopened with a comment instead of opening a new one. Empty or 0: a new ticket every time. If the ticket cannot be reopened (missing transition, deleted), a new one is created.
  • The ticket link appears on the alert, in the alert details.
  • Failures show in the channel’s “last error”. A temporary failure (service down, 429) is retried with an increasing delay; a permanent one (bad token, unknown project) is reported and not retried.
  • Send test creates a test ticket then closes it right away. If it cannot be closed, the error says so and names the ticket to close by hand.
  • Acknowledge and snooze links are not added to these channels.

Tokens are encrypted and never shown again. Create a dedicated account or token with only the rights it needs.

Works with Jira Cloud and Jira Data Center.

  • Cloud: create an API token at https://id.atlassian.com/manage-profile/security/api-tokens and give the account e-mail.

  • Data Center: Profile → Personal Access Tokens; no e-mail needed.

  • Settings — server_url, email (Cloud only; leave empty on Data Center), project (the project key), issue_type (default Task), labels (list), priority (map sets Highest, Medium or Low from the severity; none for projects without a priority field), close_transition (default Done), reopen_transition (default Reopen), reopen_hours

  • Secrets — api_token

Transitions are matched by name (of the transition or of its target status, case insensitive) among those available from the issue’s current status. If the name does not exist, the error lists the available ones.

Enable the REST API in Setup → General → API, create an API client, and copy the user’s API token from My settings → Remote access keys.

  • Settings — server_url (the GLPI address; /apirest.php is added), entity_id, category_id (numbers, optional), close_status (solved or closed), reopen_hours
  • Secrets — user_token, app_token (the API client’s application token, if it requires one)

The ticket is an incident; urgency, impact and priority follow the severity. Escalations are added as follow-ups. Reopening sets the status back to New.

Create an access token in Profile → Token Access with the ticket.agent permission.

  • Settings — server_url, group, customer (e-mail or login), close_state (default closed), reopen_state (default open), reopen_hours
  • Secrets — token

Tickets are created with an internal note; the priority is Low, Normal or High depending on the severity.

Create a fine-grained token (Settings → Developer settings) limited to the repository, with the Issues: read and write permission.

  • Settings — repository (owner/name), labels (list; they must exist), api_url (GitHub Enterprise Server only, for example https://ghe.example.org/api/v3), reopen_hours
  • Secrets — token

Resolution closes the issue as completed.

Create a project access token (or a personal one) with the api scope.

  • Settings — server_url, project (numeric id or group/project), labels (list), reopen_hours
  • Secrets — token

See The custom channel above.


The test fails immediately, with “missing setting …”. A required field is empty. The message names the exact setting.

The test fails with “no answer within 15 s”. The target server is unreachable from DumbMonit. If it is a service on your local network, check that the DumbMonit container can reach it — this is frequently a Docker networking problem, not a channel configuration problem.

The test fails with a certificate error. Your server uses a self-signed or private-CA certificate. See Self-signed certificates.

The test succeeds, but I receive nothing. The service accepted the message and sent it elsewhere: wrong channel, wrong ntfy topic, wrong Pushbullet device. Check the destination setting.

The error message contains ***. This is intended: your token was removed from the message before it was recorded. No secret ever appears in the logs, in the “last error” column, or in an API response.

Where can I see a channel’s last error? In the channel list: each row shows the date of the last successful delivery and, if any, the error of the last failure.