GLPIgram is a Telegram bot for IT service management on top of GLPI 11 (legacy REST API v1). Employees create and track tickets straight from Telegram; technicians get notified in a group chat and manage the queue with inline buttons — no GLPI-side plugins, no inbound ports, long polling only.
- Ticket creation — a guided dialog: category (live from GLPI) → urgency → title → description → optional photo/document attachments → confirm. Free text sent to the bot offers to become a ticket, too. Urgency has three ordinary levels plus a dedicated, warning-gated “🔴 Urgent (prod)” level — the only one that pings the team outside working hours.
- Account linking (AD-based) — users identify themselves by AD login or full name; a technician approves the link with one button in the tech group (anti-spoofing). Accounts disabled in GLPI/AD are unlinked automatically.
- My tickets — list of the user's open tickets with a detail view (status, assignee, recent comments, link to GLPI), adding comments and attachments, self-closing with a reason, and a rate-limited "remind the team" button.
- GLPI → Telegram sync — a polling loop announces new tickets to the tech group and pushes status changes / technician replies to the requester. Cursors are persisted in SQLite: restarts never duplicate notifications.
- Technician actions — Take / Comment / Close buttons right on the group card; solution and comment texts are collected in the technician's DM.
- Quiet hours — outside working hours, ordinary tickets (including high urgency) are queued and delivered next morning in a batch; only “🔴 Urgent (prod)” tickets go through immediately; requesters are told when the team will actually see their ticket.
- Two languages — all user-facing strings in Russian or English
(
BOT_LANGUAGE).
- GLPI 11 (tested against 11.0.4) with the legacy REST API enabled
(
apirest.php) and a service account with an API token. The GLPI 11 high-level API (/api.php, OAuth2) is not used. - Python 3.11+
- Outbound HTTPS to
api.telegram.org(anHTTPS_PROXYis honoured). No inbound connectivity needed — the bot uses long polling. - A Telegram bot token (from @BotFather) and a technician group chat.
-
Create the Telegram bot: talk to @BotFather,
/newbot, save the token. Add the bot to your technicians' group and note the group's chat id (e.g. via @getidsbot). -
Prepare GLPI: enable the API (Setup → General → API), create a service account with rights to read users/tickets and create tickets/followups, and generate its API token (user preferences → API tokens). An App-Token is optional when the bot talks to GLPI over localhost.
-
Install the bot (as root on the GLPI host):
git clone https://github.com/snnrman/glpi-tgbot.git /opt/glpi-tgbot cd /opt/glpi-tgbot sudo bash deploy/install.shThe script creates the
glpibotservice user, a venv at/opt/glpi-tgbot/venv, a data directory/var/lib/glpi-tgbotand a systemd unitglpi-tgbot.service. -
Configure:
sudo nano /var/lib/glpi-tgbot/.env # fill in the tokens, see the table below -
Start:
sudo systemctl restart glpi-tgbot journalctl -u glpi-tgbot -f # JSON logs -
In Telegram: send
/startto the bot, link your account, create a ticket.
All configuration comes from environment variables (/var/lib/glpi-tgbot/.env
under systemd). See .env.example.
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
✅ | — | Bot token from @BotFather |
TECH_GROUP_CHAT_ID |
for linking | — | Telegram group where linking is confirmed and tickets are announced |
GLPI_API_URL |
✅ | — | Base URL of apirest.php, e.g. http://127.0.0.1/apirest.php |
GLPI_APP_TOKEN |
— | empty | GLPI App-Token; usually not needed over localhost |
GLPI_USER_TOKEN |
✅ | — | API token of the GLPI service account |
GLPI_TIMEOUT |
— | 20 |
HTTP timeout for GLPI calls, seconds |
TECH_GROUP_ID |
— | — | GLPI group id whose members count as technicians |
LINK_RECHECK_TTL |
— | 300 |
Seconds between re-checks that a linked account is still active |
SYNC_INTERVAL |
— | 45 |
GLPI polling interval, seconds |
REMIND_COOLDOWN_HOURS |
— | 4 |
Min hours between reminders about the same ticket |
UNASSIGNED_REMIND_HOURS |
— | 2 |
Nag the group about New tickets older than this many working hours |
REMIND_INTERVAL_HOURS |
— | 3 |
Min working hours between repeated unassigned-nags per ticket |
TZ |
— | system | Bot timezone (GLPI dates are UTC and converted to it) |
WORK_HOURS |
— | 09:00-18:00 |
Working hours for quiet-hours handling |
WORK_DAYS |
— | 1-5 |
Working ISO weekdays, Mon=1..Sun=7 |
BOT_LANGUAGE |
— | ru |
UI language: ru or en |
WELCOME_MESSAGE |
— | — | Custom /start greeting for linked users (unlinked always get the sign-in prompt); verbatim in both languages, HTML allowed, \n for line breaks |
CATEGORY_CACHE_TTL |
— | 600 |
Category list cache, seconds |
DB_PATH |
— | /var/lib/glpi-tgbot/glpi-tgbot.sqlite3 |
SQLite database path |
LOG_LEVEL |
— | INFO |
Logging level |
HTTPS_PROXY |
— | — | Optional outbound proxy (honoured by both httpx and aiogram) |
bot/
main.py # entrypoint: dispatcher, polling, sync task
config.py # pydantic-settings (env only)
schedule.py # working-hours model for quiet hours
timeutil.py # GLPI dates are UTC -> local conversions
middleware.py # auth gate: linked users only, auto-unlink
texts/ # all user-facing strings (ru.py / en.py)
glpi/
client.py # the only module that talks HTTP to GLPI
models.py # dataclasses for tickets, users, followups
handlers/ # aiogram routers: linking, /new, /tickets, tech actions
services/
sync.py # GLPI -> Telegram polling loop + quiet-hours queue
notify.py # message rendering/sending, Telegram edge cases
attachments.py # Telegram file handling (20 MB Bot API limit)
db/
schema.sql # SQLite schema (links, cursors, queues)
repo.py # thin repository over one aiosqlite connection
deploy/ # systemd unit + install script
tests/ # pytest + respx (mocked HTTP), no live GLPI needed
Key design points:
- All GLPI HTTP lives in
glpi/client.py— sessions are renewed transparently (including GLPI's undocumented 400-on-dead-token behaviour), retries are idempotency-aware, and every failure surfaces as aGlpiErrorwith the raw API response attached. - State is SQLite (aiosqlite, WAL): account links, sync cursors, quiet-hours queue, reminder cooldowns. The bot survives restarts without duplicating any notification.
- The tech group is the trust boundary: linking requests and destructive actions are confirmed by buttons that only work inside that group.
python3 -m venv venv && venv/bin/pip install -r requirements.txt
venv/bin/pip install pytest pytest-asyncio pytest-cov respx ruff
venv/bin/ruff check . && venv/bin/ruff format --check bot tests
venv/bin/pytestSee CONTRIBUTING.md.
MIT © 2026 Oleg Kalenski