{"id":48604274,"url":"https://github.com/skrashevich/botmux","last_synced_at":"2026-04-08T23:35:50.366Z","repository":{"id":342946027,"uuid":"1175695133","full_name":"skrashevich/botmux","owner":"skrashevich","description":"Web-based command center for managing Telegram bots — multi-bot dashboard, reverse proxy, inter-bot routing, protocol bridges, and LLM-powered smart routing","archived":false,"fork":false,"pushed_at":"2026-03-23T17:37:23.000Z","size":9600,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-23T17:49:52.416Z","etag":null,"topics":["admin-panel","bot","bot-management","botapi","dashboard","docker","golang","llm-routing","longpolling","proxy","self-hosted","slack-bridge","sqlite","telegram","webhook","webupdates"],"latest_commit_sha":null,"homepage":"https://botmux.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skrashevich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-08T03:24:45.000Z","updated_at":"2026-03-23T17:37:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/skrashevich/botmux","commit_stats":null,"previous_names":["skrashevich/gobotmygod"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/skrashevich/botmux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skrashevich%2Fbotmux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skrashevich%2Fbotmux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skrashevich%2Fbotmux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skrashevich%2Fbotmux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skrashevich","download_url":"https://codeload.github.com/skrashevich/botmux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skrashevich%2Fbotmux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31579057,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admin-panel","bot","bot-management","botapi","dashboard","docker","golang","llm-routing","longpolling","proxy","self-hosted","slack-bridge","sqlite","telegram","webhook","webupdates"],"created_at":"2026-04-08T23:35:46.884Z","updated_at":"2026-04-08T23:35:50.359Z","avatar_url":"https://github.com/skrashevich.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" alt=\"BotMux\" width=\"280\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\n[![Go](https://img.shields.io/badge/Go-1.26-00ADD8?logo=go\u0026logoColor=white)](https://pkg.go.dev/github.com/skrashevich/botmux)\n[![Release](https://img.shields.io/github/v/release/skrashevich/botmux?color=blue)](https://github.com/skrashevich/botmux/releases/latest)\n[![Build](https://img.shields.io/github/actions/workflow/status/skrashevich/botmux/test.yml?label=tests\u0026logo=github)](https://github.com/skrashevich/botmux/actions/workflows/test.yml)\n[![Docker](https://img.shields.io/github/actions/workflow/status/skrashevich/botmux/docker.yml?label=docker\u0026logo=docker)](https://github.com/skrashevich/botmux/actions/workflows/docker.yml)\n[![Docs](https://img.shields.io/badge/docs-mintlify-blue?logo=readthedocs\u0026logoColor=white)](https://botmux.mintlify.app/)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n\u003c/p\u003e\n\n\u003e **[Documentation](https://botmux.mintlify.app/)** — full setup guide, API reference, and architecture overview.\n\nWeb-based command center for managing Telegram groups and channels via Bot API, with built-in reverse proxy for legacy webhook bots.\n\nGive it a bot token — it discovers which chats the bot is in, whether it has admin privileges, and provides a full-featured web dashboard for monitoring, analytics, and administration. Manage multiple bots from a single instance.\n\n## Screenshots\n\n| Login | Dashboard |\n|-------|-----------|\n| ![Login](screenshots/01-login.png) | ![Dashboard](screenshots/02-dashboard.png) |\n\n| Bot Detail | Messages |\n|------------|----------|\n| ![Bot Detail](screenshots/03-bot-detail.png) | ![Messages](screenshots/04-messages.png) |\n\n| Analytics | Admins |\n|-----------|--------|\n| ![Analytics](screenshots/05-analytics.png) | ![Admins](screenshots/06-admins.png) |\n\n| Users | Tags |\n|-------|------|\n| ![Users](screenshots/07-users.png) | ![Tags](screenshots/08-tags.png) |\n\n| Audit Log | Add Bot |\n|-----------|---------|\n| ![Audit Log](screenshots/09-audit-log.png) | ![Add Bot](screenshots/10-add-bot.png) |\n\n| User Management | API Keys |\n|-----------------|----------|\n| ![User Management](screenshots/11-user-management.png) | ![API Keys](screenshots/12-api-keys.png) |\n\n## Features\n\n### How It Works\n\n**Important:** BotMux takes over long polling for every bot it manages. Only one client can poll a bot token at a time (Telegram limitation), so:\n\n- If your bot currently **polls** (`getUpdates`) — you have two options:\n  1. **Long Polling mode** (recommended, zero code changes) — enable \"Long Poll\" in bot settings, then point your backend's API base URL to BotMux (`http://botmux:8080/tgapi/`). Your bot keeps calling `getUpdates` as before, but now gets updates from BotMux instead of Telegram.\n  2. **Push mode** — switch the backend to accept webhook-style HTTP POST requests. BotMux will poll Telegram and forward updates to your backend URL.\n- If your bot already uses **webhooks** — BotMux will switch it to polling and proxy updates back to the webhook endpoint. No changes needed on the backend side.\n\nThis applies to **all modes** — monitoring, admin actions, and reverse proxy all require BotMux to own the polling loop.\n\n**Capturing outgoing messages:** Telegram's `getUpdates` only returns incoming messages — it does not include messages sent by the bot itself. If your backend sends replies directly via `api.telegram.org`, BotMux won't see them. To fix this, point your backend at BotMux's built-in **API proxy** (`/tgapi/`) instead of `api.telegram.org`. The proxy forwards requests to Telegram transparently and captures outgoing messages into the database. See [Capturing Bot Replies](#capturing-bot-replies-api-proxy) for details.\n\n### Multi-Bot Management\n- Run multiple bots in a single instance\n- Add bots via CLI flag or through the web UI — no functional difference\n- Each bot can operate in **Management** mode (chat tracking, admin actions), **Proxy** mode (reverse proxy to legacy webhook bots), or both simultaneously\n- Per-bot status monitoring, health checks, and configuration\n\n### Reverse Proxy (Push mode)\n- Poll Telegram for updates via long polling and forward them as webhook POST requests to legacy bot backends\n- Supports `X-Telegram-Bot-Api-Secret-Token` header for backend authentication\n- Proxies webhook-style responses back to Telegram API (if backend responds with JSON containing a `method` field)\n- Periodic backend health monitoring (every 60s) with status visible in the dashboard\n- Manual health check button in the web UI\n\n### Long Polling (Pull mode)\n- External bots/backends can pull raw Telegram updates directly from BotMux instead of Telegram\n- **Telegram-compatible**: backends call `getUpdates` via the API proxy (`/tgapi/bot{TOKEN}/getUpdates`) — no code changes needed, just change the API base URL\n- Response format identical to Telegram: `{\"ok\": true, \"result\": [...]}`\n- Supports `offset`, `limit` (max 100), and `timeout` (max 60s) parameters — same semantics as Telegram's `getUpdates`\n- Enable per bot via the \"Long Poll\" toggle in bot settings\n- In-memory ring buffer (1000 updates per bot) with waiter notification for efficient long polling\n- Multiple clients can poll the same bot simultaneously\n- Works alongside push proxy — both can be active for the same bot\n- Also available via authenticated API: `GET /api/updates/poll?bot_id=X` (Bearer API key or session cookie)\n\n### Message Monitoring\n- Real-time collection of all messages and channel posts the bot can see\n- Full-text search across message history\n- Paginated message feed with sender, timestamp, and content\n- **Reply to messages** — click the reply button on any message to send a reply in-context\n- Reply chain visualization — messages show \"Replying to @user\" badge with click-to-scroll\n- Automatic chat/channel discovery — the bot detects groups it's added to\n- Soft-deleted message tracking (visually marked in the UI)\n\n### Analytics\n- Total message count, daily activity, weekly active users\n- Hourly activity distribution chart (7-day window)\n- Top 10 contributors leaderboard\n\n### Admin Actions\nRequires the bot to have corresponding admin rights in the chat:\n- **Send messages** — broadcast to any chat with HTML formatting (`\u003cb\u003e`, `\u003ci\u003e`, `\u003ccode\u003e`, `\u003ca\u003e`)\n- **Pin / unpin messages**\n- **Delete messages**\n- **Ban / unban users**\n\n### Administrator Management\n- View all chat administrators with their permission breakdown\n- **Promote users** to admin with granular permission control:\n  - Manage chat\n  - Delete messages\n  - Restrict members\n  - Invite users\n  - Pin messages\n  - Change chat info\n  - Promote other members\n- **Edit permissions** of existing admins\n- **Set custom titles** for admins (up to 16 characters)\n- **Demote** administrators\n\n### Audit Log\nEvery admin action performed through the web UI is recorded:\n- Bans and unbans\n- Message deletions and pins\n- Admin promotions and demotions\n- Title changes\n- Tag assignments\n\nThe log shows the action type, actor, target, details, and timestamp.\n\n### User Tags\nCustom classification system for chat members:\n- Assign arbitrary tags to users (VIP, Moderator, Spammer, Trusted, etc.)\n- Color-coded tags for visual distinction\n- Multiple tags per user\n- Tags are per-chat — the same user can have different tags in different chats\n\n### Inter-Bot Routing (Source-NAT)\n- Route messages between bots based on configurable conditions:\n  - **Text match** — regex pattern matching on message text (case-insensitive)\n  - **User ID** — messages from a specific Telegram user\n  - **Chat ID** — all messages from a specific chat/group\n  - **LLM (AI)** — describe the routing rule in natural language; an LLM decides which bot should handle the message\n- Three routing actions:\n  - **Forward** — sends message text as a new message via the target bot\n  - **Copy** — forwards the original message (preserving author attribution) via Telegram's `forwardMessage`\n  - **Drop** — silently ignore the message\n- **Source-NAT return path** — replies to routed messages are automatically sent back through the original source bot to the original chat, maintaining conversational context\n- Bidirectional conversation tracking: each reply creates a new mapping, enabling ongoing cross-bot dialogs\n- Route rules managed per-bot from the web UI with enable/disable toggle\n- Loop protection: bot-originated messages are not reverse-routed\n\n### Protocol Bridges\n- Bridge external messaging protocols (Slack, Discord, Meshtastic, HTTP webhooks) to Telegram bots\n- External messages are translated into Telegram Update format and injected into the bot's processing pipeline\n- All existing features work automatically: routing rules, LLM routing, reverse routing (Source-NAT), message tracking\n- **Bidirectional**: outgoing bot messages are sent back to the source protocol automatically\n- Chat and message mappings maintained for threading and reply context\n- Bridges are managed per-bot from the web UI (admin only)\n- **Generic webhook bridge**: `POST /bridge/{id}/incoming` with `{chat_id, user_id, username, text, message_id}`. Outgoing via callback URL\n- **Native Slack bridge**: full integration with Slack Events API and Web API (see setup guide below)\n- Supports any protocol via the generic webhook bridge; native protocol support available for Slack\n\n#### Slack Bridge Setup Guide\n\n**1. Create a Slack App**\n\nGo to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App** → **From scratch**.\n\n**2. Configure Bot Token Scopes**\n\nNavigate to **OAuth \u0026 Permissions** → **Scopes** → **Bot Token Scopes** and add:\n\n| Scope | Purpose |\n|-------|---------|\n| `chat:write` | Send messages to channels |\n| `users:read` | Resolve user display names |\n| `channels:history` | Receive messages from public channels |\n| `groups:history` | Receive messages from private channels |\n| `im:history` | Receive direct messages |\n| `mpim:history` | Receive group DMs |\n\n**3. Install App to Workspace**\n\nClick **Install to Workspace** and authorize. Copy the **Bot User OAuth Token** (`xoxb-...`).\n\n**4. Get the Signing Secret**\n\nGo to **Basic Information** → **App Credentials** → copy the **Signing Secret**.\n\n**5. Create a Bridge in BotMux**\n\nIn the BotMux web UI:\n1. Select a bot → **Bridges** panel → **Add Bridge**\n2. Set **Protocol** to `Slack`\n3. Set **Config** to:\n   ```json\n   {\n     \"bot_token\": \"xoxb-your-bot-token\",\n     \"signing_secret\": \"your-signing-secret\"\n   }\n   ```\n4. **Callback URL** is not needed for Slack — outgoing messages are sent directly via Slack API\n5. Enable and save\n\n**6. Configure Slack Events API**\n\n1. In Slack App settings, go to **Event Subscriptions** → toggle **Enable Events**\n2. Set **Request URL** to: `https://your-botmux-host/bridge/{id}/incoming`\n   - Replace `{id}` with the bridge ID shown in BotMux UI\n   - BotMux will automatically respond to Slack's URL verification challenge\n   - **HTTPS is required** — Slack does not accept HTTP endpoints\n3. Under **Subscribe to bot events**, add:\n   - `message.channels` — messages in public channels\n   - `message.groups` — messages in private channels\n   - `message.im` — direct messages\n   - `message.mpim` — group direct messages\n4. Save changes\n\n**7. Invite the Bot to Channels**\n\nIn Slack, invite the bot to channels where you want to receive messages:\n```\n/invite @YourBotName\n```\n\n#### How it works\n\n```\nSlack channel                    BotMux                         Telegram\n    │                              │                               │\n    │  message event (POST)        │                               │\n    ├─────────────────────────────►│  verify signature             │\n    │                              │  parse event                  │\n    │                              │  resolve username             │\n    │                              │  inject as Telegram Update    │\n    │                              ├──────────────────────────────►│\n    │                              │                               │  bot processes\n    │                              │◄──────────────────────────────┤  bot replies\n    │  chat.postMessage            │                               │\n    │◄─────────────────────────────┤  send via Slack API           │\n    │                              │  (with thread support)        │\n```\n\n- **Incoming**: Slack sends message events → BotMux verifies HMAC-SHA256 signature → translates to Telegram Update format → bot processes as a normal Telegram message\n- **Outgoing**: Bot sends a reply → BotMux calls Slack `chat.postMessage` API → message appears in the Slack channel (with thread support via `thread_ts`)\n- **Threading**: Slack thread replies are mapped to Telegram reply-to; bot replies to threaded messages maintain the thread context\n- **User names**: Display names are resolved via Slack `users.info` API (falls back to user ID)\n- **Security**: Requests are verified using HMAC-SHA256 signature (`X-Slack-Signature` header) with replay attack protection (5-minute window). **Strongly recommended** to configure `signing_secret`\n\n### LLM-Based Smart Routing\n- Uses any **OpenAI-compatible API** (OpenAI, Ollama, LM Studio, etc.) for intelligent message routing\n- The LLM receives the message text, sender info, and a list of all available bots with their descriptions and chats\n- Each bot can have a **description** explaining what it does, helping the LLM make better routing decisions\n- Configurable via the web UI: API URL, API key, model name, custom system prompt\n- Works alongside rule-based routing — LLM routing runs after traditional condition-based routes\n- Reverse routing (Source-NAT) works automatically for LLM-routed messages\n\n### Authentication \u0026 Authorization\n- **Session-based authentication** with secure HTTP-only cookies (30-day sessions)\n- **Role-based access control** — two roles: `admin` (full access) and `user` (assigned bots only)\n- **Default admin account** — auto-created on first run (`admin` / `admin`) with mandatory password change\n- **User management** — admin panel for adding, editing, and deleting users\n- **Bot access control** — many-to-many: one bot can be assigned to multiple users, one user can access multiple bots\n- **Admin delegation** — any admin can promote other users to admin role\n- **Password management** — admins can reset user passwords; users can change their own\n- **Granular UI enforcement** — non-admin users cannot see bot management, routing, or LLM configuration controls\n- **API key authentication** — Bearer token in `Authorization` header as alternative to cookies for programmatic access\n- **API key management** — admin can create, disable, and delete keys; keys are bound to users and inherit their permissions\n- Password hashing with bcrypt; API keys hashed with SHA-256\n\n### Internationalization (i18n)\n- Interface available in **English** and **Russian**\n- Language toggle button in the sidebar header (EN/RU)\n- Preference saved in localStorage and applied instantly without page reload\n\n### Media Support\n- Inline rendering of photos, videos, animations (GIF), stickers, voice messages, and audio\n- **Image lightbox** — click any photo to view full-size in an overlay (close with click or Escape)\n- WebP sticker conversion — stickers are automatically converted from WebP to PNG via [go-webp](https://github.com/skrashevich/go-webp) for universal browser compatibility\n- Video and audio players embedded directly in the message feed\n- File downloads for documents and unsupported media types\n\n### Chat Info\n- Chat ID, type, title, username\n- Member count\n- Description\n- Bot admin status\n- Last refresh timestamp\n\n## Requirements\n\n- Go 1.26+\n- A Telegram bot token (create via [@BotFather](https://t.me/BotFather))\n\n## Installation\n\n```bash\ngit clone https://github.com/skrashevich/botmux.git\ncd botmux\ngo build -o botmux .\n```\n\nOr install directly:\n\n```bash\ngo install github.com/skrashevich/botmux@latest\n```\n\n### Docker\n\n```bash\n# Run with docker compose (pulls from GitHub Container Registry)\nTELEGRAM_BOT_TOKEN=\"YOUR_TOKEN\" docker compose up -d\n```\n\nOr run the image directly:\n\n```bash\ndocker run -d -p 8080:8080 -v botmux-data:/data \\\n  -e TELEGRAM_BOT_TOKEN=\"YOUR_TOKEN\" ghcr.io/skrashevich/botmux:main\n```\n\nTo build locally (multi-arch supported):\n\n```bash\ndocker build -t botmux .\ndocker buildx build --platform linux/amd64,linux/arm64 -t botmux .\n```\n\nData is stored in the `/data` volume inside the container.\n\n## Usage\n\n### Basic (polling mode, default)\n\n```bash\n./botmux -token \"123456:ABC-DEF...\"\n```\n\nThe bot removes any existing webhook and starts long polling. Open http://localhost:8080 in your browser.\n\n### With environment variable\n\n```bash\nexport TELEGRAM_BOT_TOKEN=\"123456:ABC-DEF...\"\n./botmux\n```\n\n### Command-line flags\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `-token` | `\"\"` | Telegram bot token (or use `TELEGRAM_BOT_TOKEN` env var) |\n| `-addr` | `:8080` | HTTP server listen address |\n| `-db` | `botdata.db` | Path to SQLite database file |\n| `-webhook` | `\"\"` | Set webhook URL for receiving updates (instead of polling) |\n| `-tg-api` | `\"\"` | Custom Telegram API base URL (or `TELEGRAM_API_URL` env var) |\n| `-demo` | `false` | Enable demo mode (or `DEMO_MODE=true` env var) |\n| `-version` | `false` | Print version information and exit |\n\n### Webhook mode\n\n```bash\n./botmux -token \"TOKEN\" -webhook \"https://myserver.com/tghook\"\n```\n\nRegisters a webhook with Telegram. Updates are delivered via `POST /tghook` to your server. Requires:\n- A publicly accessible HTTPS URL\n- Port 443, 80, 88, or 8443 (Telegram requirement)\n\nThe webhook endpoint is served on the same HTTP server as the web UI. If you need HTTPS, put a reverse proxy (nginx, caddy) in front.\n\n**Note:** Webhook mode supports reverse proxy — updates received via webhook are also forwarded to the backend URL if proxy mode is enabled for the bot.\n\n### Demo mode\n\nDemo mode creates isolated per-session environments for public demonstrations. Each browser session gets its own temporary database with pre-configured bots.\n\n```bash\n# Via flag\n./botmux -demo\n\n# Via environment variable\nDEMO_MODE=true ./botmux\n\n# Docker\ndocker run -e DEMO_MODE=true -p 8080:8080 botmux\n```\n\n- Login: `demo` / `demo` (no password change required)\n- Each session gets 3 pre-configured demo bots\n- Uses a fake Telegram API (`telegram-bot-api.exe.xyz`) — no real bot tokens needed\n- Sessions expire after 30 minutes of inactivity\n- Temporary databases are cleaned up automatically on browser close or expiration\n\n### Custom Telegram API server\n\nUse `-tg-api` flag or `TELEGRAM_API_URL` env var to point botmux at a custom Telegram Bot API server (e.g., [tdlib/telegram-bot-api](https://github.com/tdlib/telegram-bot-api)):\n\n```bash\n./botmux -token \"TOKEN\" -tg-api \"http://localhost:8081\"\n```\n\n## Adding Bots\n\n### Via CLI\n\nThe bot token passed via `-token` flag or `TELEGRAM_BOT_TOKEN` env var is automatically registered as a bot. It can be configured (management, proxy, backend URL) through the web UI just like any other bot.\n\n### Via Web UI\n\nClick **+ ADD** in the sidebar to add a new bot:\n1. Enter the bot token and click **CHECK** to validate it\n2. Give it a name\n3. Enable **Management** (chat tracking, admin actions) and/or **Proxy** (reverse proxy to backend)\n4. If proxy is enabled, enter the backend webhook URL and optional secret token\n5. Click **SAVE**\n\nThe bot starts polling immediately. No restart needed.\n\n## Reverse Proxy Setup\n\nTo use botmux as a reverse proxy for a legacy webhook bot:\n\n1. Add or edit the bot in the web UI\n2. Enable **Proxy** mode\n3. Set **Backend URL** to the legacy bot's webhook endpoint (e.g., `https://legacy-bot.example.com/webhook`)\n4. Optionally set **Secret Token** (sent as `X-Telegram-Bot-Api-Secret-Token` header)\n5. Save — botmux will poll Telegram for updates and forward them as POST requests to the backend\n\nThe backend can respond with a [webhook-style reply](https://core.telegram.org/bots/api#making-requests-when-getting-updates) — JSON with a `method` field — and botmux will proxy it back to the Telegram API.\n\nUse **CHECK WEBHOOK** button in the bot detail view to verify the backend is reachable. Health is also monitored automatically every 60 seconds.\n\n## Long Polling Setup\n\nTo use BotMux as a `getUpdates` source for an existing polling bot:\n\n1. Add or edit the bot in the web UI\n2. Enable the **Long Poll** toggle in bot settings\n3. Save — BotMux will start buffering raw Telegram updates for this bot\n4. In your backend, change the Telegram API base URL:\n\n```\n# Before (direct to Telegram)\nhttps://api.telegram.org/bot{TOKEN}/getUpdates\n\n# After (via BotMux)\nhttp://localhost:8080/tgapi/bot{TOKEN}/getUpdates\n```\n\nThat's it — no other code changes needed. Your backend calls `getUpdates` with the same parameters (`offset`, `limit`, `timeout`) and gets the same response format. BotMux acts as a transparent intermediary.\n\n**How it works:**\n\n```\nTelegram ──getUpdates──\u003e BotMux (polls Telegram)\n                            │\n                            ├── saves to UpdateQueue (ring buffer, 1000 updates)\n                            ├── Management: tracks chats/messages in DB\n                            │\nBackend ──getUpdates──\u003e /tgapi/ (long poll) ──\u003e returns from UpdateQueue\nBackend ──sendMessage──\u003e /tgapi/ (proxy) ──\u003e Telegram API\n```\n\n**Notes:**\n- No additional authentication required — the bot token in the URL is the authorization (same as Telegram API)\n- Multiple backends can poll the same bot simultaneously\n- Push proxy and long polling can be active at the same time for the same bot\n- If your backend also sends messages, point those at `/tgapi/` too — see [Capturing Bot Replies](#capturing-bot-replies-api-proxy)\n- The authenticated endpoint `GET /api/updates/poll?bot_id=X\u0026timeout=T` is also available for programmatic access from the web UI or scripts\n\n### Capturing Bot Replies (API Proxy)\n\nBy default, messages sent by the backend directly via the Telegram API (e.g., `sendMessage`) are not visible to botmux — Telegram does not include a bot's own outgoing messages in `getUpdates`.\n\nTo capture these messages, botmux provides a **Telegram API proxy** at `/tgapi/`. Configure your backend to use it as the API base URL instead of `api.telegram.org`:\n\n```\n# Before (direct)\nhttps://api.telegram.org/bot{TOKEN}/sendMessage\n\n# After (via botmux proxy)\nhttp://localhost:8080/tgapi/bot{TOKEN}/sendMessage\n```\n\nThe proxy transparently forwards all requests to Telegram and returns the responses unchanged. Additionally, for message-sending methods (`sendMessage`, `sendPhoto`, `sendDocument`, `forwardMessage`, `editMessageText`, etc.), it extracts the sent message from the Telegram response and saves it to the database, so it appears in the web UI message feed.\n\nThe **API Proxy URL** is displayed in the bot detail view when proxy mode is enabled (click to copy).\n\n**Supported methods for message capture:** `sendMessage`, `sendPhoto`, `sendAudio`, `sendDocument`, `sendVideo`, `sendAnimation`, `sendVoice`, `sendVideoNote`, `sendSticker`, `sendLocation`, `sendVenue`, `sendContact`, `sendPoll`, `sendDice`, `forwardMessage`, `copyMessage`, `editMessageText`.\n\n## Architecture\n\n```\nbotmux/\n├── main.go         Entry point, flag parsing, bot registration\n├── bot.go          Telegram Bot API wrapper (all bot methods)\n├── proxy.go        ProxyManager: polling, forwarding, health checks for all bots\n├── server.go       HTTP server, REST API endpoints\n├── store.go        SQLite storage (bots, chats, messages, admin log, user tags)\n└── templates/\n    └── index.html  Single-page web application (embedded at compile time)\n```\n\n### Data flow\n\n```\nTelegram ──getUpdates──\u003e ProxyManager (polling loop per bot)\n                            │\n                            ├── Management: trackChat() / saveMessage() ──\u003e SQLite\n                            ├── Proxy (push): POST update ──\u003e Backend URL\n                            │                    │\n                            │                    └── webhook reply ──\u003e Telegram API\n                            │\n                            ├── Long Poll: enqueue ──\u003e UpdateQueue (ring buffer)\n                            │                              │\n                            │            Backend ──getUpdates──\u003e /tgapi/ ──\u003e dequeue\n                            │\n                            ├── Routing: match rules ──\u003e send via Target Bot ──\u003e Telegram\n                            │                │\n                            │                └── save mapping ──\u003e route_mappings (SQLite)\n                            │\n                            └── Reverse Route: check mappings ──\u003e reply via Source Bot ──\u003e Telegram\n                                                                       (Source-NAT return)\n\nBackend ──sendMessage──\u003e /tgapi/ (API proxy) ──\u003e Telegram API\n                            │\n                            └── capture response ──\u003e saveMessage() ──\u003e SQLite\n\nBrowser ──HTTP──\u003e Server ──API──\u003e Bot ──Bot API──\u003e Telegram\n                    │\n                    └──queries──\u003e SQLite (read)\n```\n\n### Storage\n\nSQLite with WAL mode. Tables:\n\n- **bots** — bot configurations (token, modes, backend URL, status, health)\n- **chats** — tracked chats/channels with metadata (compound PK: bot_id + chat_id)\n- **messages** — all observed messages (composite PK: chat_id + message_id)\n- **known_users** — users seen in chats\n- **admin_log** — audit trail of actions performed via web UI\n- **user_tags** — custom per-chat user classifications\n- **routes** — inter-bot routing rules (condition type/value, action, target bot/chat)\n- **route_mappings** — Source-NAT tracking of source↔target message pairs for bidirectional routing\n\nThe database file is created automatically on first run. Schema migrations run automatically.\n\n## REST API\n\nAll endpoints return JSON. Errors return `{\"error\": \"message\"}` with HTTP 500. Most endpoints require a `bot_id` query parameter.\n\n### System (no auth)\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/health` | Health check with version info |\n| GET | `/api/version` | Current version + update availability check (cached 6h) |\n\n### Bots\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/bots` | List all bots with status |\n| POST | `/api/bots/add` | Add a new bot (JSON body) |\n| POST | `/api/bots/update` | Update bot config (JSON body) |\n| POST | `/api/bots/delete?id=` | Delete a bot |\n| GET | `/api/bots/validate?token=` | Validate a bot token |\n| GET | `/api/bots/health?id=` | Check backend health |\n\n### Chats\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/chats?bot_id=` | List all tracked chats for a bot |\n| GET | `/api/chats/refresh?bot_id=\u0026chat_id=` | Refresh chat info from Telegram |\n| POST | `/api/chats/delete?bot_id=\u0026chat_id=` | Remove chat from tracking |\n\n### Messages\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/messages?chat_id=\u0026limit=\u0026offset=` | Get messages (paginated) |\n| GET | `/api/messages/search?chat_id=\u0026q=` | Search messages |\n| POST | `/api/messages/send` | Send message (JSON body: `{bot_id, chat_id, text, reply_to_message_id?}`) |\n| POST | `/api/messages/pin?bot_id=\u0026chat_id=\u0026message_id=` | Pin a message |\n| POST | `/api/messages/unpin?bot_id=\u0026chat_id=\u0026message_id=` | Unpin a message |\n| POST | `/api/messages/delete?bot_id=\u0026chat_id=\u0026message_id=` | Delete a message |\n\n### Users\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/users/list?chat_id=\u0026q=\u0026limit=\u0026offset=` | List users in a chat |\n| GET | `/api/users/profile?bot_id=\u0026chat_id=\u0026user_id=` | User profile with stats, tags, admin info |\n| POST | `/api/users/ban?bot_id=\u0026chat_id=\u0026user_id=` | Ban user |\n| POST | `/api/users/unban?bot_id=\u0026chat_id=\u0026user_id=` | Unban user |\n\n### Admins\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/admins?bot_id=\u0026chat_id=` | List administrators |\n| POST | `/api/admins/promote` | Promote user (JSON body: `{bot_id, chat_id, user_id, perms}`) |\n| POST | `/api/admins/demote?bot_id=\u0026chat_id=\u0026user_id=` | Demote admin |\n| POST | `/api/admins/title` | Set admin title (JSON body: `{bot_id, chat_id, user_id, title}`) |\n\n### Audit Log\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/adminlog?chat_id=\u0026limit=\u0026offset=` | Get admin action log |\n\n### Tags\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/tags?chat_id=` | Get all tags for a chat |\n| GET | `/api/tags/user?chat_id=\u0026user_id=` | Get tags for a specific user |\n| POST | `/api/tags/add` | Add tag (JSON body: `{bot_id, chat_id, user_id, username, tag, color}`) |\n| POST | `/api/tags/remove?id=` | Remove tag by ID |\n\n### Analytics\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/stats?chat_id=` | Chat statistics (messages, users, hourly, top contributors) |\n\n### Routes\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/routes?bot_id=` | List routing rules for a bot |\n| POST | `/api/routes/add` | Add route (JSON body: `{source_bot_id, target_bot_id, condition_type, condition_value, action, target_chat_id, enabled, description}`) |\n| POST | `/api/routes/update` | Update route (JSON body with `id`) |\n| POST | `/api/routes/delete?id=` | Delete route |\n\n### Long Polling\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/updates/poll?bot_id=\u0026offset=\u0026limit=\u0026timeout=` | Poll for updates (auth required) |\n\n### Telegram API Proxy\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| ANY | `/tgapi/bot{TOKEN}/{method}` | Proxies to `api.telegram.org`, captures sent messages |\n| GET/POST | `/tgapi/bot{TOKEN}/getUpdates` | Returns updates from BotMux queue (if long poll enabled) |\n\n## Bot Setup\n\n1. Create a bot via [@BotFather](https://t.me/BotFather)\n2. Disable [privacy mode](https://core.telegram.org/bots/features#privacy-mode) if you want the bot to see all group messages (BotFather → `/setprivacy` → Disable)\n3. Add the bot to your group or channel\n4. Make it an administrator (with the permissions you need)\n5. Run botmux — the chat will appear in the sidebar automatically\n\n### Required bot permissions\n\nFor full functionality, the bot should be an admin with:\n- **Delete messages** — to delete messages from the UI\n- **Ban users** — to ban/unban\n- **Pin messages** — to pin/unpin\n- **Invite users** — for invite link management\n- **Add new admins** — to promote/demote other admins\n- **Change group info** — to modify chat settings\n\nThe bot works with any subset of these permissions — features that require missing permissions will return errors when used.\n\n## Resource Requirements\n\nBotmux is a lightweight single-binary application with minimal resource needs.\n\n| Resource | Minimum | Recommended | Notes |\n|----------|---------|-------------|-------|\n| **CPU** | 1 core | 1–2 cores | Each bot runs as a lightweight goroutine |\n| **RAM** | 20–30 MB | 50–100 MB | Pure Go, no CGO. Grows with number of bots and message volume |\n| **Disk** | ~16 MB (binary) | 100+ MB | SQLite DB grows with stored messages and chats |\n| **Docker image** | ~25–30 MB | — | Alpine-based, stripped binary |\n\n**Network:**\n- Port 8080 (HTTP) for the web UI and REST API\n- Outbound HTTPS to `api.telegram.org` (long polling per bot)\n- Outbound to backend URL (if proxy mode is enabled)\n- Outbound to LLM API endpoint (if LLM routing is enabled)\n\n**Scaling reference:** A minimal VPS (1 vCPU, 512 MB RAM, 10 GB disk) comfortably handles dozens of bots and thousands of messages per day.\n\n## Security Notes\n\n- The web UI requires **authentication** — a default admin account (`admin` / `admin`) is created on first run with mandatory password change.\n- For production use, place the server behind a reverse proxy with HTTPS (nginx, caddy, etc.).\n- The SQLite database contains all collected messages. Protect the `botdata.db` file accordingly.\n- Bot tokens are sensitive. Use environment variables or secure flag passing, not shell history.\n\n## License\n\nApache License 2.0 — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskrashevich%2Fbotmux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskrashevich%2Fbotmux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskrashevich%2Fbotmux/lists"}