Как это работает
Сервис стоит на зарубежном сервере и работает посредником между Telegram и сайтами на RU-серверах, которые не могут достучаться до api.telegram.org напрямую.
- Каждый бот поллит Telegram (getUpdates). Полученные апдейты сначала записываются в очередь на диске, и только потом подтверждаются в Telegram, поэтому при перезапуске ничего не теряется.
- Очередь доставляется на сайт
{web_url}{update_path}строго по порядку. Если сайт недоступен, сервис повторяет попытки с паузой до 5 минут и копит апдейты до 24 часов. - Сайт отправляет сообщения через
/api/v1/{bot_id}/..., сервис выполняет их в Telegram.
Апдейты на сайт
POST {web_url}{update_path}
X-Service-Token: {service_token бота}
X-Update-Id: 123456789
Content-Type: application/json
{ "bot_id": "sol-prod", "message": { ...объект message из Telegram... } }
{ "bot_id": "sol-prod", "callback_query": { ... } }
Ключ в теле совпадает с типом апдейта (message, callback_query, edited_message, my_chat_member и т.д.). Какие типы получать, задаётся в настройках бота. По умолчанию только message и callback_query, как раньше.
Как сервис понимает ответ сайта:
- 2xx: доставлено.
- 401, 403, 404, 408, 429, 5xx, таймаут, сеть: сайт недоступен или неправильно настроен, апдейт остаётся первым в очереди и повторяется.
- Остальные 4xx: сайт отклонил именно этот апдейт, он уходит в dead и не блокирует остальные. То же после 8 ответов 5xx подряд на один апдейт.
Dead-апдейты видны во вкладке «Очередь», их можно переотправить.
API для сайтов
Все запросы POST /api/v1/{bot_id}/... с заголовком X-Service-Token и JSON-телом. Без {bot_id} в пути запрос уходит боту default (старые клиенты).
| Путь | Тело | Метод Telegram |
|---|---|---|
| /messages/send | { chat_id, text, options } | sendMessage |
| /messages/edit | { text, options: { chat_id, message_id, ... } } | editMessageText |
| /messages/edit-reply-markup | { reply_markup, options: { chat_id, message_id } } | editMessageReplyMarkup |
| /messages/delete | { chat_id, message_id } | deleteMessage |
| /callback/answer | { callback_query_id, options } | answerCallbackQuery |
| /commands/set | { commands: [{ command, description }] } | setMyCommands |
| /raw | { method, params } | любой метод |
| /bot/reload-token | { token } | смена токена бота |
Ответ: результат Telegram как есть (для /raw обёрнут в { ok: true, result }).
Ошибка Telegram: HTTP 502 и тело
{ "error": "ETELEGRAM: 403 Forbidden: bot was blocked by the user", "error_code": 403 }
При 429 от Telegram с коротким retry_after (до 5 с) сервис сам ждёт и повторяет один раз.
Пример
curl -X POST https://resolve.leden4ik.name/api/v1/sol-prod/messages/send \
-H "X-Service-Token: $SECRET" -H "Content-Type: application/json" \
-d '{"chat_id":123456,"text":"Привет","options":{"parse_mode":"HTML"}}'
Health-check
GET /healthz, без авторизации, для мониторинга (UptimeRobot и т.п.).
{
"status": "ok", // "degraded", если у какого-то бота проблемы
"service": "bot",
"polling": true, // все включённые боты поллят
"bots": [ { "id": "sol-prod", "polling": true, "healthy": true, "queue": 0 } ]
}
Настройки сервера (.env)
| BOT_ADMIN_USER / BOT_ADMIN_PASS | вход в панель, без них панель закрыта |
| BOT_PORT, BOT_HOST | порт (3001) и адрес (127.0.0.1, сервис стоит за nginx) |
| DATA_DIR | где лежит база и бэкапы (./data) |
| QUEUE_MAX_AGE_HOURS | сколько хранить недоставленные апдейты (24) |
| EVENTS_RETENTION_DAYS | сколько хранить журнал (7) |
| PROXY_URL | HTTP-прокси до Telegram, нужен пакет undici |
| TELEGRAM_API_URL | свой Bot API сервер вместо api.telegram.org |