Notification Channels
Get notified when agents request approval. Six channel types, three with interactive approve/deny buttons.
Right page if: you need to choose between notification channels, configure routing filters, or understand which channels support interactive approve/deny buttons. Wrong page if: you need setup steps for a specific channel -- see https://docs.edictum.ai/docs/console/notifications/telegram, https://docs.edictum.ai/docs/console/notifications/slack, https://docs.edictum.ai/docs/console/notifications/discord, https://docs.edictum.ai/docs/console/notifications/email, or https://docs.edictum.ai/docs/console/notifications/webhook. Gotcha: routing filters use AND logic across dimensions but OR logic within a dimension. An empty filter means "receive everything" for that dimension, not "receive nothing."
Get notified when agents request approval. Six channel types, three with interactive approve/deny buttons.
Channel Types
| Channel | Interactive | Notes |
|---|---|---|
| Telegram | Yes | Bot token + chat_id. Inline keyboard buttons. |
| Slack App | Yes | Bot token + signing secret. Block Kit action buttons. |
| Slack Webhook | No | Incoming webhook URL. One-way notification with dashboard link. |
| Discord | Yes | Bot token + public key. Component buttons. |
| Webhook | No | Generic HTTP POST. Optional HMAC-SHA256 signature. |
| No | SMTP. HTML email with dashboard deep link. |
Interactive channels let you approve or deny directly from the notification (click a button in Telegram, Slack, or Discord). Non-interactive channels send a notification with a link to the dashboard where you can decide.
Adding a Channel
Dashboard > Settings > Notifications > Add Channel.

Select the channel type, fill in the configuration fields, and click Test to verify.
Routing Filters
Each channel can have routing filters that control which approval requests it receives:
| Filter | Format | Example |
|---|---|---|
environments | List of exact environment names | ["production", "staging"] |
agent_patterns | Glob patterns matched against agent_id | ["prod-*", "ops-agent"] |
contract_names | Glob patterns matched against the contract name | ["block-*", "require-approval-*"] |
How Filters Are Evaluated
Filters are evaluated at notification send time, not when the channel is created. This means you can update filters on a channel and the new filters apply immediately to future approval requests.
AND logic across dimensions. All non-empty filter dimensions must match. If you set both environments: ["production"] and agent_patterns: ["prod-*"], the channel only receives approvals from agents matching prod-* in the production environment.
OR logic within a dimension. Each filter field is a list. A match against any item in the list satisfies that dimension. Setting environments: ["production", "staging"] matches approvals from either environment.
Empty filter = receive everything for that dimension. A channel with no filters receives all approval requests. A channel with only environments set receives all agents and all contracts in those environments.
Pattern Syntax
agent_patterns and contract_names use Python's fnmatch module for pattern matching. The patterns are case-sensitive (fnmatchcase).
| Pattern | Matches | Does not match |
|---|---|---|
prod-* | prod-api, prod-billing-v2 | staging-api, PROD-api |
*-deploy | ci-deploy, prod-deploy | deploy, deploy-v2 |
agent-? | agent-1, agent-a | agent-12, agent- |
[!t]* | agent-1, prod-api | test-agent |
require-*-approval | require-deploy-approval | require-approval |
Supported wildcards:
| Wildcard | Meaning |
|---|---|
* | Matches everything |
? | Matches any single character |
[seq] | Matches any character in seq |
[!seq] | Matches any character not in seq |
Examples
| Goal | Filters |
|---|---|
| Production alerts only | environments: ["production"] |
| Prod and staging (OR) | environments: ["production", "staging"] |
| One team's agents | agent_patterns: ["platform-*"] |
| Specific contract alerts | contract_names: ["require-human-approval"] |
| Deploy contracts only | contract_names: ["*-deploy", "*-deploy-*"] |
| Everything | Leave all filters empty |
Routing Scenarios
Slack for production, Discord for staging:
Create two channels with environment filters:
| Channel | Type | environments |
|---|---|---|
prod-alerts | Slack App | ["production"] |
staging-alerts | Discord | ["staging"] |
Both channels can have empty agent_patterns and contract_names to receive all approvals in their respective environments.
Email only for deploy contracts:
| Channel | Type | contract_names |
|---|---|---|
deploy-email | ["*-deploy", "approve-deploy-*"] |
This channel only receives approvals triggered by contracts whose name matches the deploy patterns. All other approvals are ignored.
Telegram for one team's agents, webhook for everything else:
| Channel | Type | agent_patterns |
|---|---|---|
ml-team-telegram | Telegram | ["ml-*", "data-*"] |
catch-all-webhook | Webhook | (empty -- receives everything) |
The Telegram channel receives approvals from ml-* and data-* agents. The webhook receives all approvals, including those same agents. Filters do not create exclusive routing -- a single approval can match multiple channels and be sent to all of them.
Production deploys by a specific team (AND logic):
| Channel | Type | environments | agent_patterns | contract_names |
|---|---|---|---|---|
infra-prod-deploys | Slack App | ["production"] | ["infra-*"] | ["*-deploy"] |
All three dimensions must match: the environment is production, the agent ID starts with infra-, and the contract name ends with -deploy.
Security
Secrets Encrypted at Rest
Channel configuration secrets (bot tokens, signing secrets, API keys, SMTP passwords) are encrypted at rest using NaCl SecretBox. In API responses, secrets are masked (e.g. edk_****mHz).
HTTPS Requirement
Interactive channels (Telegram, Slack App, Discord) require EDICTUM_BASE_URL to be set to a public HTTPS URL. The console must be reachable from the internet for button callbacks to work.
Sending notifications works without HTTPS. Receiving button clicks does not.
Test Button
Every channel has a test button:
POST /api/v1/notifications/channels/{id}/testOr click Test in the dashboard. A test message is sent to verify the configuration is correct.
Channel Lifecycle
- Add a channel in Settings > Notifications
- Test to verify configuration
- Enable/disable with the toggle -- disabled channels don't send notifications
- Edit to update configuration or filters
- Delete to remove permanently
Next Steps
Last updated on