Notifications
When something happens that a person should know about — a server goes offline, a daemon key is revoked, access is granted — TurboPanel writes it to the bell of everyone concerned, and delivers it to any channel a rule routes it to: an email address, a chat room, a webhook. This chapter is the bell, Account → Notifications (/account/notifications), and what an operator can expect from delivery.
Private alpha — the catalogue is short on purpose
Only events that the platform actually raises are listed; today that is six. Each new emitter joins the catalogue in the same commit as the code that raises it, so what the rules matrix offers is always what can arrive.
The model
| Term | Meaning |
|---|---|
| Event | One thing that happened, with a stable code (server.offline), a severity (info, warning, critical) and a scope: it belongs to one organization, or to the instance as a whole. |
| Inbox | Your own rows behind the bell. A server event lands in the inbox of every member of that organization; the events that mirror the audit trail — deletes, key revokes, grant changes — reach only its owners and managers; an instance event reaches every instance administrator. No setup needed. |
| Channel | Somewhere outside the console a notification can be delivered. Yours (they follow your account across organizations), the organization's (managers edit them), or the instance's — an administrator's receivers that hear every event on the instance, managed through the admin API for now. Kinds: email, webhook, slack, discord, telegram. |
| Rule | What a channel receives: every event at or above a severity floor, or a chosen list of events. A channel with no rule receives nothing. |
| Delivery | One attempt ledger per event × channel: written before the send, retried on failure with backoff, abandoned after five attempts. |
Three facts:
- A channel's address is a credential. A webhook URL's path is the secret, and so is a bot token. They are stored sealed under the instance's data-encryption key and never shown again — the screen shows the origin, or the last few characters.
- Addresses must be
httpswith no credentials in the URL. That is the whole rule: a LAN receiver (an Alertmanager next to the control plane, a10.xaddress, a bare hostname) is allowed on every runtime. A hosted instance cannot reach a private address, so a delivery there simply fails and is recorded as such. - Delivering never blocks the thing being reported. A webhook that is down does not stop a deploy or a sweep; it leaves a failed delivery that the maintenance tick retries.
The events
| Code | Severity | Scope | Inbox | When |
|---|---|---|---|---|
server.offline | critical | organization | every member | The daemon stopped answering and the server was marked offline. |
fleet.mass_disconnect | critical | instance | administrators | A whole sweep lost its fleet at once — usually the control plane's own network or broker. |
server.deleted | info | organization | owners and managers | A server was deleted from the console. |
server.daemon_key_revoked | warning | organization | owners and managers | A server's daemon key was revoked. |
access.grant_created | info | organization | owners and managers | A permission grant was added. |
access.grant_revoked | warning | organization | owners and managers | A permission grant was removed. |
The bell
The bell in the header (the avatar badge on the phone apps) shows your unread count, polled once a minute. Open it for the newest rows: a coloured dot for severity, the title and the sentence, when it happened. Mark all read clears the badge; × dismisses a row; a row that names a server opens that server. Notification settings at the bottom opens the preferences screen.
Add a channel
Account → Notifications. Two panels: Your channels and Organization channels (the organization you last opened; only a manager may add or edit there).
Pick the kind — Email, Webhook, Slack, Discord or Telegram — and give the channel a Name.
Enter the address: an email address — your own for a personal channel, a member's account email for an organization one (other addresses wait for a verification flow that does not exist yet); an https URL that accepts a JSON POST; a Slack or Discord incoming-webhook URL; or, for Telegram, your bot token, a slash, then the chat id (123456:ABC…/987654321). For a webhook you may add a signing secret.
Choose the rules: Every event at a floor (Everything, Warnings and up, Critical only), or switch to Chosen events and tick them. Add channel.
Each channel is then a row with its rules (change them and Save rules), Pause / Resume, Remove, and the outcome of the last delivery in the past week.
What a receiver gets
| Kind | Body |
|---|---|
| Webhook | JSON: event, severity, title, body, text (the one-line form), organizationId, target ({ type, id } or null), context (small non-secret facts), at. Headers X-TurboPanel-Event: <code> and, when the channel has a signing secret, X-TurboPanel-Signature: sha256=<hex> — HMAC-SHA256 of the raw body with the secret. |
| Slack | { "text": "…" } — the title, the sentence, then key=value facts in parentheses. Mattermost and Rocket.Chat read the same field. |
| Discord | { "content": "…" }, the same line. |
| Telegram | sendMessage to the chat id with the same line. |
Subject [TurboPanel Critical] Server db-1 went offline; the sentence, the facts as a list, and an Open in TurboPanel button when the event has a target. |
Verify a webhook signature by computing sha256= + hex(HMAC-SHA256(secret, raw body)) and comparing it to the header with a constant-time comparison.
Delivery and retries
One attempt is made at the moment of the event, with a five-second budget per channel; the retry sweep leaves a fresh row alone for two minutes so a slow attempt is never sent twice. A failure — a non-2xx answer, a timeout, a refused address — is recorded with a short code (http_503, timeout, network, address_scheme_not_https) and retried by the maintenance tick after 1, 5, 25 and 125 minutes; after the fifth failure the delivery is abandoned. Email deliveries ride the instance's mailer queue (self-hosted: RabbitMQ → the mailer service; High Availability: Mailgun) and are subject to its own retry. The channel row shows the last delivery's status and how many attempts it took.
Reference
| Item | Value |
|---|---|
| Kinds | email · webhook · slack · discord · telegram (push is registered by the store apps, never typed) |
| Severities | info < warning < critical |
| Rule | * at a floor, or one row per event |
| Inbox fan-out | server events: every organization member; audit-mirroring events: owners and managers; instance events: every instance admin |
| Channel reach | organization channels, its members' own channels, and every instance channel |
| Address rule | https, no credentials in the URL; any host, LAN included |
| Retry | 1 → 5 → 25 → 125 minutes, five attempts, then abandoned |
| Signature | X-TurboPanel-Signature: sha256=<hex HMAC-SHA256 of the raw body> |
| Name | ≤ 80 characters; address ≤ 2048; signing secret ≤ 256 |
Errors
| Code | Status | Meaning |
|---|---|---|
address_rejected | 422 | The URL failed the outbound gate; reason says which rule (scheme_not_https, credentials_in_url, malformed). |
address_invalid, address_required | 400 | Not an email address / not a token-slash-chat-id pair / empty. |
address_not_a_member | 422 | An email channel may only name your own address, or a member's account email for an organization channel. |
label_required, label_invalid | 400 | The name is missing, too long, or has control characters. |
signing_secret_not_applicable | 400 | Only a webhook channel signs its deliveries. |
signing_secret_invalid | 400 | 1–256 characters. |
rule_event_unknown | 400 | A rule names an event that is not in the catalogue (reason carries it). |
rule_severity_invalid, rules_invalid | 400 | The rule list is malformed. |
kind_invalid, scope_invalid | 400 | Not one of the kinds above, or not user / organization. |
Forbidden | 403 | Organization channels need organization:manage. |
Not found | 404 | The channel or the inbox row is not yours. |
Encryption unavailable — no encryption key configured | 503 | The instance has no root secret, so a sealed address cannot be stored. |
Related
- Servers — what
server.offlineand a revoked key mean. - Organizations, teams and access — the grants the access events describe.
- Administering an instance — the operator's instance-wide alert webhook.
- Troubleshooting — configuring that webhook from the shell.
Last updated on
Datacenters and networking
The organization's network registry — datacenters (subnets, member pins, priority and trust, per-datacenter defaults), the address pool, Docker networks and host address pools, reserved ranges, and the TurboFabric mesh — with every collision and refusal code
Account security
Signing in, two-factor with an authenticator app, backup codes, passkeys, linking GitHub and Google, what re-authentication is, which changes sign your other devices out, and every refusal