# Heimdallr: one notification endpoint for Bark, WeCom, Telegram and the rest

> Heimdallr is a small FastAPI service that fans one inbound webhook out to many push channels, deploys to Vercel or Zeabur at near zero cost, and speaks the Bark, message-pusher and PushDeer APIs so existing clients need no change. The configuration is entirely environment variables, and the v2 rewrite is not compatible with v1.

**LeslieLeung/heimdallr** — 一个非常轻量的通知网关，可以聚合各种推送渠道，使用 Serverless 部署，几乎零成本运行。

- Repository: https://github.com/LeslieLeung/heimdallr
- Website: https://heimdallr.zeabur.app/docs
- Stars: 813 · Forks: 74
- Language: Python
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/leslieleung-heimdallr

## A gateway whose job is to fan one request out to many

Heimdallr is described as a very lightweight notification gateway that aggregates various push channels, deployable on serverless platforms and running at almost zero cost. The shape is straightforward. One HTTP endpoint receives a notification, a group decides which channels are enabled for it, and each enabled channel delivers the message through its own protocol. The README positions it as the equivalent of a free, open source, self-hosted version of the newer Server酱, with no restrictions. The list of supported destinations is long and specific: Bark, WeCom application messages, WeCom robot webhooks, PushDeer, Chanify, Pushover, email, Discord webhooks, Telegram bots, ntfy, Feishu and Lark, DingTalk custom robots, Apprise, PushMe and Quote0/MindReset. Two entries, Chanify and Pushover, are marked as untested, which is worth noting before you rely on them.

## Compatibility APIs are what make it drop-in

The most useful design decision is the compatibility layer. Heimdallr provides an interface fully compatible with Bark and an interface compatible with message-pusher, and the rule is simple: on any service that supports Bark or message-pusher, you replace the service URL with Heimdallr's URL and the messages go out through Heimdallr to all the other channels. The message-pusher shape is a URL of the form https://<domain>/push/<username>, which becomes https://<domain>/competable/message-pusher/push with the token set to Heimdallr's group token. The PushDeer shape is https://<domain>/message/push, which becomes https://<domain>/competable/pushdeer/message/push with the pushkey set to the PushDeer token. That means an existing monitoring script, a home automation rule or a NAS webhook can keep its URL format and gain a dozen delivery channels at once, which is a much smaller change than rewriting each integration.

## Groups and channels are declared entirely in environment variables

There is no configuration file to edit. The .env.example at the repository root shows the whole model, and it is a two-level structure. ENABLED_GROUPS names the groups, for example group_1 and group_2, and each group has an ENABLED_CHANNELS list naming the channels it uses and a TOKEN that identifies it to callers. Each channel then has a TYPE and its own type-specific keys. channel_1 is a Bark channel with a BARK_URL and a BARK_KEY, channel_3 is a WeCom application channel with a CORP_ID, an AGENT_ID and a SECRET, channel_7 is an email channel with HOST, PASSWORD, PORT, STARTTLS, TO and USER, channel_8 is a Discord webhook with a WEBHOOK_ID and a WEBHOOK_TOKEN, channel_9 is Telegram with a TOKEN and a CHAT_ID, and channel_10 is ntfy with a HOST and a TOPIC. The prefix convention means any channel can be renamed and only its own lines change.

## Deploying it means a Vercel clone button or a Zeabur template

Serverless deployment is the point of the project, and two hosts are documented with one-click buttons. Vercel gets a Deploy with Vercel button that clones the repository into a new project, and Zeabur gets a Deploy on Zeabur button pointing at a template, with a note that the configuration approach follows Zeabur's environment variable documentation and that you paste the contents of your .env into the raw environment variable editor. Two more deployment paths exist as documentation rather than buttons: Tencent Cloud Serverless and Alibaba Cloud Serverless, each with its own file under docs/deploy. A Docker path is also documented and supports both arm64 and amd64 architectures, and the Dockerfile at the root shows the shape of the container. It starts from python:3.13.5-slim, creates an unprivileged appuser, installs poetry with virtualenvs disabled, copies pyproject.toml and poetry.lock and runs poetry install without the dev group, copies the heimdallr package and main.py, and finishes with CMD ["python", "main.py"]. There is also a configuration generator hosted at heimdallr-configurator.vercel.app that produces the environment file for you.

## FastAPI and Apprise do the transport and the fan-out

The runtime stack is visible in the pyproject. It is a Poetry project named heimdallr with package-mode set to false, requiring Python 3.11 and later. The server is FastAPI with uvicorn, requests handles outbound HTTP, python-multipart covers form parsing, environs reads the environment configuration, and apprise is the library that gives the project its breadth of channels. The README makes Apprise the reason there will never be a missing notification channel, linking to its supported notifications list, and it also notes that image sending is supported through Apprise only. The rest of the stack is unremarkable and worth noting for what it implies about maintenance, since apprise 1.7.4 is a floor rather than a pin and the requirements.txt is a hash-locked file generated for reproducible installs. The dev group is pre-commit, black, isort, autoflake and memray, so memory profiling is part of the project's own habit.

## Markdown is opt-in, and the syntaxes differ per channel

Formatting is a per-request decision rather than a global setting. On services that support Markdown, formatted text can be rendered as Markdown, and you request it by passing msg_type = markdown as a query parameter or in the JSON body. The example in the README shows both forms, a GET with the parameters in the URL and a POST with a JSON payload carrying key, title, body and msg_type. The caveat is the interesting part, and the README states it plainly: not every Markdown-capable service uses the same syntax, and on services that do not support Markdown the content is displayed as plain text. The three services listed as supporting Markdown are WeCom, Discord and Telegram, and the README links each one's documentation for the exact dialect, because Telegram in particular uses its own MarkdownV2 style and the bold and italic markers used by the other two are not the same syntax there. Sending a message is a plain request, either as a GET with the parameters in the path and query string:

```bash
curl 'http://<HOST>/<TOKEN>/*Hello*/__World__?msg_type=markdown'
```

or as a POST with a JSON body:

```bash
curl -X POST 'http://<HOST>/push' --data-raw '{
    "key": "<TOKEN>",
    "title": "*Hello*",
    "body": "__World__",
    "msg_type": "markdown"
}'
```

## A v2 rewrite that breaks v1 configuration, and one licence

The notice at the top of the README is a compatibility warning that anyone with an existing deployment needs to read. The project has been refactored into a new version whose API and configuration items are not compatible with the original v1.x line, and users who need the old one are pointed to the legacy branch. So the current main branch is a breaking rewrite rather than an incremental update, and the legacy code is kept alive on a side branch rather than deleted. The licence is GPL-3.0, declared in the pyproject and in the LICENSE file at the root, which is worth pausing on if you plan to run it as a service for a team, since a copyleft licence attaches obligations to modification and distribution. The repository is not archived and the last push was on 2026-10-19. The published releases are v2.1.0 on 2025-03-18, v2.1.1 on 2025-04-13 and v2.2.0 on 2025-07-19, so the tagged line and the branch have moved at different speeds.

## Conclusion

Adopt Heimdallr if you have several notification destinations and one service that needs to reach all of them, especially if any of your existing clients already speak the Bark or message-pusher API. Do not adopt it if you need per-recipient routing rules, delivery receipts or anything beyond a fan-out, because the documented behaviour is that groups name a fixed set of enabled channels. Before you commit, copy .env.example, define your groups and channels, and check the docs/Config.md page, since the whole configuration surface lives in environment variables rather than in a file the README lists.

## FAQ

### What is Heimdallr?

It is a very lightweight notification gateway that aggregates many push channels, deployed on serverless platforms for near zero running cost. It supports Bark, WeCom, PushDeer, Chanify, Pushover, email, Discord, Telegram, ntfy, Lark, DingTalk, Apprise, PushMe and others through one HTTP endpoint.

### How do I configure Heimdallr's channels and groups?

Entirely through environment variables. ENABLED_GROUPS names the groups, each group has an ENABLED_CHANNELS list and a TOKEN, and each channel has a TYPE plus type-specific keys prefixed with the channel name. The .env.example file at the repository root shows the pattern and there is a configuration generator hosted at heimdallr-configurator.vercel.app.

### Can I point an existing Bark or message-pusher client at Heimdallr?

Yes. The README states that any service supporting Bark or message-pusher can have its service URL replaced with Heimdallr's, and that Heimdallr then delivers the message through its own channels. For message-pusher the URL becomes https://<domain>/competable/message-pusher/push, and for PushDeer it becomes https://<domain>/competable/pushdeer/message/push.

### Is Heimdallr compatible with the older v1.x release?

No. The project has been refactored into a new version whose API and configuration items are not compatible with the original v1.x line, and the old code is kept on a legacy branch. The licence is GPL-3.0 and the last push was on 2026-10-19.

## Sources

- [LeslieLeung/heimdallr on GitHub](https://github.com/LeslieLeung/heimdallr)
- [License: GPL-3.0](https://github.com/LeslieLeung/heimdallr/blob/main/LICENSE)
- [Project website](https://heimdallr.zeabur.app/docs)
- [README](https://github.com/LeslieLeung/heimdallr/blob/main/README.md)
- [Releases](https://github.com/LeslieLeung/heimdallr/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/leslieleung-heimdallr
