Telegram Call Service
REST-сервис: POST /call → делает настоящий 1-на-1 звонок (p2p call,
такой же, как обычный звонок в приложении Telegram — с гудком и ожиданием
ответа) указанному пользователю под вашим аккаунтом и озвучивает переданный
текст через TTS сразу после того, как вызываемый принял звонок.
Как это устроено
Telegram Bot API не умеет звонить — это принципиальное ограничение платформы,
никакой код это не обойдёт. Настоящий голосовой звонок доступен только через
MTProto-аккаунт обычного пользователя (Pyrogram-форк pyrofork + py-tgcalls,
низкоуровневый биндинг ntgcalls).
Библиотека py-tgcalls делает это через phone.requestCall / phone.acceptCall
с DH key exchange — ровно тот же путь, которым идёт обычный звонок из
приложения. play() блокирует выполнение, пока собеседник не ответит (или не
истечёт CALL_RING_TIMEOUT), бросает TimedOutAnswer / CallDeclined /
CallBusy, если не дозвонились.
⚠️ Важно понимать риски
- Это автоматизация личного аккаунта, а не бота. Telegram может ограничить или заблокировать аккаунт за автоматизированные действия, особенно при частом/массовом использовании. Используйте выделенный номер, не основной.
- API_ID/API_HASH и session-файл дают полный доступ к аккаунту — храните
.envиsessions/так же бережно, как пароль. - Не используйте это для звонков посторонним людям без их согласия.
- Звонок реально дозвонится только если у вызываемого аккаунта в Settings → Privacy and Security → Calls разрешены звонки от вашего аккаунта (например, "Everybody", или вы у него в контактах). Иначе Telegram тихо отклонит попытку на уровне privacy — это ограничение платформы, не бага сервиса.
Настройка
1. Получить API_ID / API_HASH
https://my.telegram.org → API development tools → создать приложение.
2. Настроить .env
cp .env.example .env
# заполнить API_ID, API_HASH, PHONE_NUMBER, CALL_TARGET, API_TOKEN
CALL_TARGET — кому звонить по умолчанию: @username вызываемого аккаунта
(или его numeric user id). Убедитесь, что у вызывающего аккаунта этот
пользователь виден (например, есть в контактах) — иначе resolve_peer не
сможет найти адресата по username при первом обращении.
3. Один раз залогиниться (интерактивно, вне обычного запуска)
docker compose build
docker compose run --rm callsvc python scripts/login.py
Введите код из Telegram (и пароль 2FA, если включён). Session-файл сохранится
в ./sessions/ на хосте и будет переиспользоваться при обычном запуске.
4. Запуск сервиса
docker compose up -d
API
GET /health
Проверка живости.
POST /call
curl -X POST http://localhost:8000/call \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"text": "Внимание! Сработал алерт на проде."}'
Поля тела запроса:
| поле | обязательное | описание |
|---|---|---|
| text | да | текст, который будет озвучен (TTS, до 2000 символов) |
| target | нет | @username или numeric user id вызываемого. Если не задан — берётся CALL_TARGET из .env |
Если API_TOKEN в .env не задан — заголовок Authorization не требуется.
Ответ (после того, как собеседник принял звонок и TTS проигрался):
{"status": "called", "target": "@monster1025", "duration": 4.2}
Ошибки:
409— не дозвонились: не ответили заCALL_RING_TIMEOUTсекунд, отклонили, заняты, звонок сброшен, либо звонок на эту цель уже идёт, либоtargetрезолвится в группу/канал (сервис звонит только пользователям).401— неверный/отсутствующий Bearer-токен (еслиAPI_TOKENзадан).500— прочие ошибки (см. логиdocker compose logs -f).
Ограничения текущей версии
- Один одновременный звонок на цель (защищено локом), параллельные запросы
на разные
targetобрабатываются независимо. - Озвучка через gTTS требует исходящего доступа в интернет из контейнера.
POST /callсинхронно ждёт ответа на звонок (доCALL_RING_TIMEOUTсек) — учитывайте это в таймауте клиента, который дёргает ручку.