Pulsarr is a real-time event relay for security teams, routing alerts from systems like Wazuh and Shuffle into human response channels.
Detect. Route. Respond.
The attack happened. The log exists. The question is whether it reached the right human in time.
Pulsarr is not a SIEM. Pulsarr is not a compliance platform. Pulsarr is the relay. The channel between your infrastructure and the humans defending it.
- A webhook-driven alert routing service.
- A normalization and rendering layer for incident payloads.
- A deterministic bridge from detection systems to response channels.
- A backend-first foundation for future multi-destination event routing.
- Receives JSON events via POST to /alert.
- Protects the endpoint with API key validation.
- Normalizes minimum and enriched payload shapes.
- Renders structured, readable Telegram messages.
- Supports HTML-safe output with escaping and truncation for long logs.
- Exposes health endpoint and production-friendly deployment paths.
Telegram is the first destination implemented, not the final one.
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#161A2C",
"primaryTextColor": "#E2E8F0",
"primaryBorderColor": "#7C6FF7",
"lineColor": "#4FC9E0",
"secondaryColor": "#111420",
"tertiaryColor": "#0A0D14",
"background": "#0A0D14",
"mainBkg": "#161A2C",
"secondBkg": "#111420",
"clusterBkg": "#111420",
"clusterBorder": "#2A3047",
"fontFamily": "Inter"
}
}}%%
flowchart LR
%% SOURCES
subgraph SOURCES["Detection Sources"]
WZ["Wazuh<br/>SIEM / EDR Events"]
SH["Shuffle<br/>SOAR Playbooks"]
AU["Custom Automations<br/>n8n · Scripts · APIs"]
end
%% INGEST
WH["Webhook Ingress<br/>Event Intake Layer"]
%% CORE
subgraph PULSARR["Pulsarr Event Relay"]
NR["Normalize<br/>Parse · Enrich · Deduplicate"]
RD["Render<br/>Human-readable alert formatting"]
RT["Route<br/>Priority · Escalation · Delivery"]
end
%% OUTPUT
AL["/alert"]
TG["Telegram<br/>Human Response Channel"]
%% FLOW
WZ --> WH
SH --> WH
AU --> WH
WH --> NR
NR --> RD
RD --> RT
RT --> AL
AL --> TG
%% STYLES
classDef source fill:#111420,stroke:#4FC9E0,color:#E2E8F0,stroke-width:1.5px;
classDef core fill:#161A2C,stroke:#7C6FF7,color:#E2E8F0,stroke-width:2px;
classDef output fill:#1E2435,stroke:#A99BFF,color:#E2E8F0,stroke-width:1.5px;
classDef accent fill:#0E2435,stroke:#17A8CC,color:#E0F7FF,stroke-width:2px;
class WZ,SH,AU source;
class WH,NR,RD,RT core;
class AL accent;
class TG output;
Typical deployment today: Wazuh + Shuffle + custom automations -> Pulsarr /alert -> Telegram human response channel
./install.shpython3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .envThen set at least these values in .env:
- TELEGRAM_BOT_TOKEN
- TELEGRAM_CHAT_ID
- API_KEY
Run locally:
./run.shHealth check:
curl http://localhost:8000/healthHeaders:
- Content-Type: application/json
- X-API-Key: your API key (when API_KEY is configured)
Minimum payload:
{
"message": "SSH auth failures detected"
}Enriched example:
{
"message": "Multiple SSH authentication failures detected",
"source": "wazuh",
"orchestrator": "shuffle",
"severity": "high",
"level": 9,
"rule_id": "5716",
"agent": "servidor-web-01",
"agent_ip": "192.168.10.50",
"target_user": "root",
"source_ip": "203.0.113.78",
"source_port": "54321",
"decoder": "sshd",
"log_source": "/var/log/auth.log",
"full_log": "May 15 14:32:18 servidor-web-01 sshd[12345]: Failed password for root from 203.0.113.78 port 54321 ssh2",
"event_type": "SSH authentication failure",
"affected_endpoint": "/ssh",
"workflow": "telegram-test"
}curl -X POST http://localhost:8000/alert \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"message": "Multiple SSH authentication failures detected",
"source": "wazuh",
"orchestrator": "shuffle",
"severity": "high",
"rule_id": "5716",
"agent": "servidor-web-01"
}'Required:
- TELEGRAM_BOT_TOKEN
- TELEGRAM_CHAT_ID
Recommended:
- API_KEY
Operational:
- HOST (default 0.0.0.0)
- PORT (default 8000)
- LOG_LEVEL (default INFO)
- INCLUDE_RAW_JSON (default false)
- TELEGRAM_PARSE_MODE (kept for compatibility)
- GUNICORN_WORKERS (default 3)
- Systemd unit file is currently named systemd/telegram-alert-sender.service for compatibility with existing setups.
- Docker Compose currently keeps a compatibility service key name.
- Operational names can be migrated in a dedicated deployment migration step later.
- Configurable sources (beyond current webhook conventions)
- Mapping engine for source-specific normalization
- Template editor for destination-specific rendering
- Multiple destinations (Telegram first, then Slack/Teams/email/webhooks)
- Frontend/admin panel for route management and observability
- Use strong API keys and rotate them.
- Keep .env out of version control.
- Restrict source IPs when possible.
- Prefer reverse-proxy TLS termination in production.
MIT. See LICENSE.