HTTP API (служебные эндпоинты)
Этот документ описывает служебные HTTP‑маршруты aiohttp‑приложения Telegram‑бота (telegram-bot/main.py). Эти маршруты вызываются другими сервисами (в первую очередь MCP‑сервером) для уведомлений и доставки документов.
Базовые требования к переменным окружения и запуску описаны в разделе Конфигурация и окружение.
Note
Эти эндпоинты задуманы как внутренние (межсервисные): обычно они доступны только в приватной сети/локально и вызываются MCP‑сервером.
Warning
Авторизации на уровне приложения нет. Если по ошибке опубликовать эти маршруты наружу (например, через публичный ingress/reverse‑proxy), их можно будет вызвать без токена. Убедитесь, что они недоступны извне (firewall/allowlist, private network и т. п.).
Tip
Частый сценарий: webhook Telegram нужно открыть наружу, а служебные эндпоинты — нет.
В таком случае наружу прокидывают только WEBHOOK_SECRET_PATH (и иногда /health), а доступ к /cargo-assigned и /cargo-docx ограничивают по сети (internal ingress / allowlist / отдельный порт).
GET /health и GET /
Назначение: health‑check сервиса.
Ответ (200):
{ "status": "ok", "service": "telegram-bot" }
POST /cargo-assigned (уведомление клиенту)
Кто вызывает: MCP‑сервер, когда по заявке клиента найден/подтверждён перевозчик (см. mcp-server/prime_lardi/notifications.py).
Что делает обработчик: генерирует текст уведомления через OpenAI и отправляет его в Telegram Business‑чат клиенту.
Требования к окружению
BUSINESS_CONNECTION_IDдолжен быть задан (иначе сервис не сможет отправлять проактивные сообщения в бизнес‑чат и вернёт 422).OPENAI_API_KEYдолжен быть задан и рабочий (иначе генерация текста упадёт и будет 500).
Что важно знать (поможет избежать сюрпризов)
- Этот эндпоинт вызывает OpenAI для генерации текста → это тратит токены.
- Успешный вызов не только отправляет сообщение, но и может записать служебный контекст в БД:
- обновляет
user_state.doc_flow(включает режим документов и сохраняетdoc_context); - добавляет запись в
dialogue_history(в том числеcontent_type="system"сdoc_context). - Если Telegram вернул 403 при отправке (например, бизнес‑соединение устарело), эндпоинт вернёт 500 с сообщением вида:
business connection expired, нужен новый входящий месседж. BUSINESS_CONNECTION_IDберётся не «из воздуха»: это значение из Telegram Business. Его можно увидеть во входящихbusiness_messageкак полеbusiness_connection_id(удобнее всего — включить DEBUG‑логирование и посмотреть payload обновления).
Запрос
- Content‑Type:
application/json - Тело запроса: JSON‑объект
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
tg_id |
int |
да | Telegram chat id клиента (положительное число). |
request_id |
int |
да | Идентификатор заявки (положительное число). |
cargo |
object |
да | Контекст заявки (см. ниже). |
Минимально обязательные поля внутри cargo:
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
content_name |
string |
да | Название груза. |
source_towns |
string[] |
да | Города загрузки (непустой список непустых строк). |
target_towns |
string[] |
да | Города выгрузки (непустой список непустых строк). |
payment_value |
number |
да | Сумма оплаты (число). |
currency_name |
string |
да | Валюта оплаты. |
Ответ
200 OK (уведомление отправлено):
{ "ok": true, "chat_id": 123456789, "request_id": 100500 }
Ошибки:
400— невалидный JSON или тело запроса не объект.422— не пройдена валидация полей (tg_id,request_id, обязательные поля внутриcargo), либо отсутствуетBUSINESS_CONNECTION_ID.500— ошибка генерации текста или отправки сообщения в Telegram.
Формат ошибок (обратите внимание на ключ error):
{ "ok": false, "success": false, "error": "..." }
Пример curl
curl -sS -X POST 'http://localhost:8081/cargo-assigned' \\
-H 'Content-Type: application/json' \\
-d '{
"tg_id": 123456789,
"request_id": 100500,
"cargo": {
"content_name": "Палети",
"source_towns": ["Київ"],
"target_towns": ["Львів"],
"payment_value": 25000,
"currency_name": "UAH"Ы
}
}'
POST /cargo-docx (доставка DOCX пользователю)
Кто вызывает: MCP‑сервер из инструмента send_docx_form (см. mcp-server/prime_lardi/docx_sender.py).
Что делает обработчик: принимает DOCX как файл, отправляет его пользователю и копию ответственному аккаунту через Telethon.
Требования к окружению
RESPONSIBLE_TG_IDдолжен быть задан (иначе 500).- Telethon должен быть настроен и успешно инициализирован при старте сервиса:
TELETHON_API_ID,TELETHON_API_HASH,TELETHON_SESSION;- сессия должна быть авторизована (иначе отправка файлов упадёт).
Что важно знать (поможет избежать сюрпризов)
- Эндпоинт реально отправляет файл в Telegram через Telethon (это отправка «как пользователь», а не как бот).
- Telethon может вернуть 422
recipient not found in telethon dialogs, если аккаунт Telethon не видит получателя в своих диалогах. Обычно это значит, что с этим пользователем ещё не было переписки/контакта в аккаунте Telethon. - При успешной отправке сервис также обновляет
user_state.doc_flow.last_docx_sent_at(если удалось найти пользователя поtg_id). - Если
RESPONSIBLE_TG_IDзадан и отличается отtg_id, копия DOCX отправится ответственному аккаунту. Это тоже может упасть с ошибкой Telethon.
Запрос
- Content‑Type:
multipart/form-data - Поля формы:
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
tg_id |
string |
да | Telegram chat id клиента (будет приведён к int). |
file |
файл | да | DOCX файл (любые байты; MIME проверкой не ограничен). |
caption |
string |
нет | Подпись к файлу в Telegram. |
request_id |
string |
нет | Идентификатор заявки (сейчас используется только для логов). |
Ответ
200 OK (файл отправлен):
{ "success": true, "message": "Sent", "chat_id": 123456789 }
Ошибки:
400— некорректный multipart.422— невалидныйtg_id, отсутствуетfileили файл пустой, либо Telethon не нашёл получателя в диалогах.500— Telethon/отправка упали, либо не настроенRESPONSIBLE_TG_ID.
Формат ошибок (обратите внимание на ключ message):
{ "ok": false, "success": false, "message": "..." }
Пример curl
curl -sS -X POST 'http://localhost:8081/cargo-docx' \\
-F 'tg_id=123456789' \\
-F 'caption=DOCX по заявке' \\
-F 'request_id=100500' \\
-F 'file=@./example.docx'