A notification channel is a place Citadel posts messages to for your organization: an email list, a Telegram chat, or a Slack or Mattermost channel. Channels live in the console under Settings → Notification channels. Each one shows how its last delivery went and has a Send test message button. A delivery log of the latest messages is under the list. Anyone who can see the organization’s settings sees the channels and the log. Adding, changing, testing, switching off and removing a channel needs the permission to manage the organization’s settings (security.manage). Every change is written to the organization’s event log, with who made it and which fields changed. A secret’s value never goes into the log.

Kinds

Email

Citadel sends email through its own email service. You do not configure a mail server. One email goes to all of the channel’s recipients. It has an HTML part and a plain-text part. The subject is the subject prefix, if you set one, followed by the message title or its first line. Type the recipients separated by commas or new lines. Citadel lowercases them and drops duplicates.

Telegram

Telegram messages are posted by your own bot:
  1. Create a bot: send /newbot to @BotFather and copy the token it gives you.
  2. Add the bot to the group. For a channel, add it as an administrator, because only an administrator can post there.
  3. Send any message in that chat. Then open https://api.telegram.org/bot<token>/getUpdates and copy chat.id. A group’s id starts with -100. A public channel can also be given as @name.
The bot token is stored encrypted. Once you save it, the console shows only its last four characters. To change the token, type the new one in. A blank field keeps the saved token. Telegram allows about one message per second to a chat, and fewer to a group. Citadel spaces messages to the same chat to stay under these limits. Text longer than Telegram’s 4096 characters is sent as plain text and cut off at the limit.

Slack

A Slack channel connects in one of two ways. Choose it with Connect with in the channel’s form. Bot token — messages are posted by your own Slack app, and files are attached:
  1. Create a Slack app in your workspace. Under OAuth & Permissions, add the bot scopes chat:write and files:write.
  2. Install the app to the workspace and copy its Bot User OAuth Token. It starts with xoxb-.
  3. Invite the app to the channel: type /invite @your-app in the channel.
  4. Copy the channel id. It is at the bottom of the channel’s details and looks like C0123456789.
A message with files is one Slack message: the files, with the text as their comment. Incoming webhook — the simplest setup, but text only. Add an incoming webhook to your Slack app and pick the channel. Copy the webhook URL. It must be on https://hooks.slack.com/. Files go as download links in the text. Slack allows about one message per second to a channel. Citadel spaces messages to the same channel to stay under this limit.

Mattermost

A Mattermost channel also connects with a bot token or an incoming webhook. Bot token — messages are posted by a bot account on your server, and files are attached:
  1. Create a bot account (Integrations → Bot Accounts) and copy its access token.
  2. Add the bot to the team and to the channel.
  3. Copy the channel id: in the channel, open View Info. The id is at the bottom.
  4. Enter the address your team opens Mattermost at, such as https://chat.example.com.
Citadel uploads the files first and then creates one post with the text and all the files, so a message appears whole or not at all. A post carries up to 5 files; any more go as download links. Text longer than 16,383 characters is sent as plain text and cut off at the limit. Incoming webhook — text only. Create an incoming webhook for the channel (Integrations → Incoming Webhooks) and copy its URL. Files go as download links in the text.

Bot tokens and webhook URLs

Bot tokens and webhook URLs are stored encrypted. Once you save one, the console shows only its last four characters. To change it, type the new one in. A blank field keeps the saved value. When you switch a channel to the other way of connecting, the saved token or URL of the old way is deleted.

Addresses Citadel calls

Citadel calls a server or webhook URL you enter only if it is safe to reach from the internet:
  • The URL starts with https:// and has no user name or password in it.
  • Its host resolves to public internet addresses only. A host that points to a private network, the local machine, a link-local or cloud metadata address, or another reserved address is refused.
  • Citadel connects to the address it checked, and never follows a redirect. A server that answers with a redirect fails the delivery.
The check runs when you save the channel and again before every message. If the host stops resolving, the delivery is retried. If it now points to an address that is not allowed, the delivery fails as refused by the channel.

Message format

Messages are written in a small subset of Markdown. Each channel renders it in its own format: Anything else appears as you typed it. Citadel escapes text for each channel, so a message can never inject markup into an email or a chat. Text in a message never mentions anyone: @channel, @here, @all or @name in the text does not notify people in Slack or Mattermost. Words that people chose to be notified about in their own Slack or Mattermost settings still notify them. When a channel cannot take a file — it is too large, or the channel is an incoming webhook, which carries text only — the message carries a download link instead. The link opens that one file and nothing else. It works without signing in to the console and expires after 7 days. The message shows the expiry date. Anyone who has the link can download the file until then, so share it only as you would share the file. The link opens a short page that downloads the file, so the browser needs JavaScript. The secret part of the link comes after #: the browser keeps it and sends it to the console only in the body of the download request. It never appears in an address that a server, a proxy or a link preview records.

In workflows

One workflow step posts to notification channels: Send a notification. It names channels from your organization’s settings. It never holds a bot token, a chat id or a webhook URL itself. To send a report, the step attaches it: see Sending a report.

Send a notification

The step saves its result as notification:
When the step does not wait, each status is the one at the moment the step ran, usually pending.

Values in a message

In a title or a message, {name} puts in a value of the run. It can be something an earlier step saved, such as {movement.amount}, {wallet.reference} or {report.period}. These values are in every run: A value is shown exactly as it is. A character such as * or [ in a value never turns into formatting, in any channel. To use a value as a link, write it as the link’s target: [Open the run]({run.url}). This works when the value is a plain http or https URL; otherwise the link shows as text. A missing value puts in nothing.

Sending a report

Generate a report only builds the report. To send it, put a Send a notification step after it and pick the report in Attach reports. On the report step, Add “Send a notification” after it adds that step with the report attached and a message that names the report and its period. The report step saves the report as report, or under the name in Save the report as, with id, title, period and format. The message and the title can use these values, such as {report.title} and {report.period}. The deliveries wait while the report is being built. If the report cannot be built, they fail as not sent. A failed delivery is retried from the delivery log; the report is not built again. For the workflow to act on a failed delivery, set Then to Wait until every channel has it and continue on the failed path.

Publishing and the run page

A workflow publishes only if every channel its steps name exists in your organization’s settings. Steps built before notification channels — the Send to Telegram step, or a chat id or webhook URL typed into a step — no longer publish or run. Choose channels in Send a notification, then publish the workflow again. A Generate a report step that still has its own channels, title or message, from when a report step could send the report itself, no longer publishes or runs either. On that step, Move to a “Send a notification” step moves them to a new step after it, with the report attached. Then publish the workflow again. On a run’s page, a step that posted a message lists each channel’s delivery. Delivery log opens the log of that run, where a failed delivery can be retried.

Delivery

A message gets one delivery for each channel it goes to. A worker restart or a repeated request never sends the same message to a channel twice. The delivery log shows each one: A delivery is tried up to 6 times: at once, then after 15 s, 1 min, 5 min, 30 min and 1 h. When a channel answers too many requests, Citadel waits as long as the channel asks. That wait does not use up an attempt. A delivery stops waiting after 24 hours. A delivery fails without further attempts when: Retry in the log sends a failed delivery again with a fresh schedule. The log can show the deliveries of one channel, or those of one workflow run.

Switching off and removing

A channel that is switched off takes no messages. New and waiting deliveries to it fail with the channel is disabled. Switch it on again to resume; deliveries that failed meanwhile are retried by hand. You cannot remove a channel while a published workflow posts to it. The channel’s form lists those workflows: change them first. Past deliveries stay in the log after the channel is removed.