# Notifications
URL: https://synquic.tech/docs/guides/notifications.md

Get told when a deploy fails, an app goes down, a disk fills up or a certificate can't renew, by email, webhook, Slack, Discord, Microsoft Teams, Telegram, ntfy, Gotify, Pushover, Mattermost or Matrix.

import { Step, Steps } from 'fumadocs-ui/components/steps';

Synq can tell you about the things that need you: a failed deploy, an app that crashed, a server running out
of disk, a certificate that couldn't renew. You decide **where** messages go (channels) and **what** you want to
hear about (events).

<Callout title="Where this lives">
Open **Settings** and choose the **Notifications** tab, or go to **`/settings?tab=notifications`**. It has two
sections: **Delivery channels** and **What to be notified about**.
</Callout>

Channels belong to you: every member of the organization sets up their own. You only get notifications about
projects, servers and other resources you have access to.

## Add a channel

<Steps>

<Step>

### Open Add channel

Under **Delivery channels**, press **Add channel** and pick the kind from the row of logos: **Email**,
**Webhook**, **Slack**, **Discord**, **Microsoft Teams**, **Telegram**, **ntfy**, **Gotify**, **Pushover**,
**Mattermost** or **Matrix**.

</Step>

<Step>

### Fill in the fields

Every channel needs a **Label** ("Label (e.g. On-call email)") so you can tell your channels apart. The other
fields depend on the kind; see [Channel setup](#channel-setup) below. Press **Add channel**; the toast says
"Channel added".

</Step>

<Step>

### Send a test

A new channel shows **Unverified**, and unverified channels receive nothing. Press **Send test**. Synq sends a
real test message through the channel ("Synq test notification", saying the channel is configured correctly).
If it arrives, the channel turns **Verified** and the toast says "Test sent". If it fails, the toast shows the
service's own error, with any secret removed; fix the settings and test again.

</Step>

</Steps>

To remove a channel, press its delete button and confirm "Delete this channel? Subscriptions using it will
stop." Secrets you enter (webhook URLs of chat services, tokens) are stored encrypted and never shown again;
the list only says whether they are set.

## Channel setup

| Channel | Fields | Where to get them |
| --- | --- | --- |
| **Email** | Email address | Any address. The instance must be able to send mail (below). |
| **Webhook** | URL, for example `https://example.com/synq-hook` | Your own endpoint that accepts a JSON `POST`. |
| **Slack** | Webhook URL `https://hooks.slack.com/services/...` | Slack: create an app with **Incoming Webhooks** and add a webhook to a channel. |
| **Discord** | Webhook URL `https://discord.com/api/webhooks/...` | Discord: **Server Settings → Integrations → Webhooks → New Webhook**, then **Copy Webhook URL**. |
| **Microsoft Teams** | Webhook URL, for example `https://prod-00.westus.logic.azure.com/workflows/...` | A Power Automate **Workflows** webhook (a URL on `*.logic.azure.com`), or a legacy incoming webhook connector (`*.webhook.office.com`). |
| **Telegram** | Bot token from @BotFather; Chat ID, for example `-1001234567890` | Create a bot with @BotFather, then message the bot (or add it to your group) so it's allowed to reply. A group's ID is negative; a public channel can be given as `@channelname`. |
| **ntfy** | Topic, for example `synq-alerts`; Server URL (leave empty for `https://ntfy.sh`); Access token (optional) | Subscribe to the same topic in the ntfy app. On the public server anyone who knows the topic can read it, so pick a hard-to-guess name or use an access token. Topics use letters, digits, `-` and `_`, up to 64 characters. |
| **Gotify** | Gotify server URL, for example `https://gotify.example.com`; Application token | In Gotify, open **Apps**, create an application, and paste its token. |
| **Pushover** | User or group key; Application API token | Your user key is on the Pushover dashboard. Register an application there to get its API token. Both are 30 letters and digits. |
| **Mattermost** | Webhook URL `https://mattermost.example.com/hooks/...`; Channel override (optional, for example `town-square`) | Mattermost: **Integrations → Incoming Webhooks → Add**. The URL must end in `/hooks/<id>`. |
| **Matrix** | Homeserver URL, for example `https://matrix.org`; Room ID or alias, for example `!abc123:matrix.org`; Access token of the sending account | Use a dedicated bot account: invite it to the room, then paste its access token. |

### Email needs a way to send mail

Email notifications go out through the instance's outgoing mail (SMTP under **Settings → Email**, or the
built-in mail server). If none is set up, the form warns "No email server is set up on this instance, so email
notifications won't be delivered." with **Set up SMTP →**, and **Send test** fails with that reason instead of
pretending to work. Messages arrive with the subject `[Synq] <event>`.

### Webhooks

Synq sends a `POST` with `Content-Type: application/json` and `User-Agent: Synq-Webhook/1.0`:

```json
{
  "id": "d8c1...",
  "category": "deploy.failed",
  "organizationId": "org_...",
  "resourceType": "deployment",
  "resourceId": "dep_...",
  "payload": { "eventType": "deployment.failed", "...": "event details" },
  "createdAt": "2026-09-26T10:15:00.000Z"
}
```

Each request carries `X-Synq-Signature-256: sha256=<hex>`, an HMAC-SHA256 of the raw body with the channel's
signing secret. Synq generates the secret when the channel is created. The panel doesn't display it: to verify
signatures, create the channel through the API (the response includes the signing secret once, as `secret`) or
set your own with `hmacSecret`. See the [Notifications API](/docs/api/notifications).

The receiver must answer `2xx` within 10 seconds. Redirects are not followed.

### Receivers on your own network

By default Synq only delivers to public `https://` addresses. To send to a webhook, ntfy, Gotify, Mattermost or
Matrix server on your private network (or to plain `http://`), set `NOTIFY_WEBHOOK_ALLOW_INTERNAL=true` in
`~/.synq/compose/.env` on the server and apply it the same way as the
[certificate authority settings](/docs/guides/https-certificates#certificate-authority-settings).

### In-app

The in-app channel stores notifications inside Synq instead of sending them anywhere. It isn't offered in **Add
channel**: create it through the API (`kind: "in_app"`, verified straight away) and read it with
`GET /api/notifications/deliveries`. The panel doesn't have an inbox view for it yet.

## Choose what to be notified about

**What to be notified about** is a table of events. Tabs across the top filter it: **All**, **Deployment**,
**App health**, **Backups**, **Jobs**, **Domains & SSL**, **Members** and **Mail**.

Each row has:

| Column | Who | What it does |
| --- | --- | --- |
| **Delivery channels** | Admins | Which kinds of channel the organization default sends to (email if nothing is chosen). |
| **Organization defaults** | Admins | Whether the event is on by default for members. |
| **Notify me** | Everyone | Your own choice. Ticking or unticking it sets the event on or off for **all your channels**. |

How the two levels combine:

- If you have made your own choice for an event (**Notify me**), that is what happens, on all your verified
  channels.
- If you haven't, the organization default applies: when the event is on, it goes to your verified channels of
  the default kinds.

So an admin can make sure everyone hears about failed deploys by email, and each member can still turn events on
or off for themselves. The checkbox is disabled until you have a channel ("Add a channel first to subscribe to
events.").

Two things to know:

- **Notify me** covers the channels you have when you tick it. After adding a new channel, untick and tick the
  event again to include it.
- The organization default only reaches channels of its **Delivery channels** kinds, email unless an admin
  chose others. If your only channel is, say, Slack, tick **Notify me** for the events you want (or ask an admin
  to add Slack to the defaults).

## Events

| Tab | Event | On by default | Sent when |
| --- | --- | --- | --- |
| Deployment | **Deploy failed** | yes | A build or deploy fails. Includes the error and a snippet of the failing log. |
| Deployment | **Deploy succeeded** | no | A deploy succeeds (also a redeploy with nothing to change, titled "No changes to deploy"). |
| Deployment | **Deploy cancelled** | no | A running deploy is cancelled. |
| App health | **App down** | yes | A container that should run has exited, died or was killed for running out of memory. Includes the exit code and last log lines. Never for a service you stopped yourself. |
| App health | **App crash looping** | yes | A container keeps restarting. |
| App health | **App unhealthy** | yes | A container is up but its own healthcheck fails. |
| App health | **App autoscaled** | yes | [Autoscaling](/docs/guides/replicas#autoscaling) added or removed a replica (with the load that caused it), or could not add one because the server was short of memory. |
| App health | **App recovered** | yes | An outage ended. |
| App health | **Server unreachable** | yes | Synq can't reach a server's Docker. One alert per server, and a "Server reachable" all-clear when it's back. |
| App health | **Server disk almost full** | yes | Root disk passed its threshold (85% by default). |
| App health | **Server memory high** | yes | Memory passed its threshold (90% by default). |
| App health | **Server CPU high** | yes | CPU stayed above its threshold (90% for 10 minutes by default). |
| Backups | **Backup failed** | yes | A scheduled or manual backup fails. |
| Backups | **Backup succeeded** | no | Each successful backup. |
| Backups | **Restore completed** | yes | A restore finishes, or fails. |
| Jobs | **Job failed** | yes | A job run fails. |
| Jobs | **Job succeeded** | no | A job run succeeds. |
| Jobs | **Job started** | no | A job run starts. |
| Domains & SSL | **SSL cert expiring** | yes | The daily renewal job couldn't renew a certificate that expires within 14 days. (The description in the panel still says 7 days; the 14-day rule is what the job uses.) |
| Domains & SSL | **Domain verification failed** | yes | A verification started from the API or the CLI (`synq domain verify`) fails. In the panel, the live log shows the failure instead. |
| Members | **New member joined** | no | Someone accepted an invitation. |
| Members | **Member removed** | no | A member was removed. |
| Members | **Invitations sent** | no | An admin sent invitations. |
| Mail | **Mail arrived at a watched address** | no | A message reached a mailbox or domain watched by a rule under **Emails**. |

Server thresholds are set per server; see [Server monitoring and alerts](/docs/guides/server-monitoring#alert-thresholds).
App health events come from the **Container health watch** job, which checks containers once a minute; each
outage sends at most an alert, an escalation and a recovery, not one message per minute.

## Urgency on push channels

ntfy, Gotify, Pushover and Matrix get a priority that matches the event:

| Urgency | Events | ntfy | Gotify | Pushover | Matrix |
| --- | --- | --- | --- | --- | --- |
| Critical | App down, App crash looping, Server unreachable | 5 (urgent) | 10 | 1 (high) | `m.text` |
| High | Deploy, backup and job failures, App unhealthy, server thresholds, SSL cert expiring, Domain verification failed | 4 | 8 | 1 (high) | `m.text` |
| Normal | App recovered, Restore completed, test messages | 3 | 5 | 0 | `m.notice` |
| Low | Successes, job starts, member changes, watched mail | 2 | 2 | -1 (quiet) | `m.notice` |

Pushover's emergency priority, which repeats until acknowledged, is never used.

## Delivery and retries

Messages are queued and sent within seconds. A failed send is retried, up to 5 attempts in total; after that the
delivery is marked failed with the service's error. A message is dropped if its channel was deleted, disabled or
is no longer verified, or if the recipient lost access to the resource.

## Related

<Cards>
  <Card title="Monitoring page" href="/docs/dashboard/monitoring" description="The same problems, as issues you can see and fix." />
  <Card title="Server monitoring and alerts" href="/docs/guides/server-monitoring" description="Set the thresholds behind the server alerts." />
  <Card title="Notifications API" href="/docs/api/notifications" description="Channels, subscriptions, defaults and deliveries over HTTP." />
</Cards>
