tg_client WebSocket Docs: Cloud Media Uploads
Що це за flow
Це окремий сценарій для відправки медіа через Telegram без локального upload з фронта на бекенд.
Клієнт спочатку отримує presigned PUT URL, заливає файл напряму в storage,
а потім викликає send_message або send_comment з media.key.
- WS:
create_tg_media_upload_url - HTTP:
PUTbinary уupload_url - WS:
send_messageабоsend_commentзmedia - TDLib піднімає
updateFileGenerationStart, бекенд підтягує файл із storage і завершує generation
Усередині TDLib використовується inputFileGenerated + cloud_fetch_v1,
а не текстове посилання на файл.
Підтримувані типи
| media.type | TDLib тип | Примітка |
|---|---|---|
document | inputMessageDocument | Будь-який файл, PDF, ZIP, DOCX, а також фото/відео "без стискання". |
photo | inputMessagePhoto | З підтримкою show_caption_above_media, has_spoiler, self_destruct_type. |
video | inputMessageVideo | З підтримкою thumbnail, cover, supports_streaming, has_spoiler. |
audio | inputMessageAudio | Music/audio track з title, performer, album_cover_thumbnail. |
voice_note | inputMessageVoiceNote | Native voice message. Для коректного UI бажано .ogg + Opus. |
video_note | inputMessageVideoNote | Native "відеокружечок". Обов'язково передати length. |
Для photo і video прапори high_quality,
without_compression, disable_compression, send_as_document,
as_document, preserve_quality перемикають відправку в document.
Крок 1. Отримати upload URL
{
"action": "create_tg_media_upload_url",
"userbot_id": 1,
"filename": "clip.mp4",
"content_type": "video/mp4",
"chat_id": "123",
"media_type": "video"
}
Відповідь:
{
"type": "create_tg_media_upload_url",
"result": {
"upload_url": "https://storage.example/...",
"key": "tg/outgoing/userbot_1/chat_123/video/fixedid.mp4",
"expires_in": 600,
"source": "outgoing/userbot_1/chat_123/video",
"content_type": "video/mp4"
}
}
key треба зберегти. Саме він передається в send_message або send_comment.
upload_url одноразовий/тимчасовий і в Telegram не відправляється.
Крок 2. Завантажити файл у storage
HTTP-запит до upload_url:
PUT {upload_url}
Content-Type: video/mp4
Body: binary file
Postman
- Створи звичайний HTTP request
- Method:
PUT - URL: встав
upload_url - Body →
binary - Header
Content-Typeмає збігатися зresult.content_type
Важливо
- Не використовуй
form-data - Не додавай
Authorization - Успішна відповідь зазвичай
200або204
Крок 3. Відправити повідомлення в Telegram
Базовий текстовий upload/send flow:
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"text": "caption",
"media": {
"type": "video",
"key": "tg/outgoing/userbot_1/chat_123/video/fixedid.mp4",
"file_name": "clip.mp4",
"expected_size": 1234567
}
}
text стає caption для media. Якщо потрібно, можна замість нього передати
media.caption і media.caption_entities.
Для альбому передайте media_items масивом. Top-level text і entities
будуть застосовані до першого елемента як caption fallback.
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"text": "Album caption",
"entities": [
{
"offset": 0,
"length": 5,
"type": { "@type": "textEntityTypeBold" }
}
],
"media_items": [
{
"type": "photo",
"key": "tg/outgoing/userbot_1/chat_123/photo/one.jpg",
"file_name": "one.jpg"
},
{
"type": "video",
"key": "tg/outgoing/userbot_1/chat_123/video/two.mp4",
"file_name": "two.mp4",
"supports_streaming": true
}
],
"reply_to": {
"replyToMsgId": "555"
},
"protect_content": true
}
Альбом підтримує 2-10 елементів. TDLib групує лише photo, video,
document і audio; для document і audio
усі елементи мають бути того самого типу. reply_markup для альбомів не підтримується.
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"media_items": [
{
"type": "forward",
"from_chat_id": "-100555000111",
"message_id": "9001",
"without_sender": true,
"caption": "Copied forward",
"caption_entities": [
{
"offset": 0,
"length": 6,
"type": { "@type": "textEntityTypeItalic" }
}
],
"show_caption_above_media": true
},
{
"type": "forward",
"from_chat_id": "-100555000111",
"message_id": "9002"
}
]
}
Для comments flow використовуйте send_comment і передайте
comments_meta або пару discussion_chat_id + message_thread_id.
{
"action": "send_comment",
"userbot_id": 1,
"comments_meta": {
"discussion_chat_id": "-100999000777",
"message_thread_id": "9001"
},
"text": "caption",
"entities": [
{
"offset": 0,
"length": 7,
"type": { "@type": "textEntityTypeBold" }
}
],
"media": {
"type": "document",
"key": "tg/outgoing/userbot_1/chat_123/document/fixedid.pdf",
"file_name": "report.pdf",
"expected_size": 123456
},
"protect_content": true
}
Загальні top-level поля для send_message / send_comment
Усі поля нижче однаково підтримуються і для send_message, і для send_comment. Для comments відрізняються лише target-поля: discussion_chat_id / comments_meta / message_thread_id.
| Поле | Обов'язковість | Що робить |
|---|---|---|
userbot_id | required | ID userbot listener-а. |
chat_id | required для send_message | Чат, куди відправляємо. |
discussion_chat_id | optional | Comments chat для send_comment. Може прийти явно або через comments_meta. |
text | optional | Caption для media або звичайний текст, якщо media нема. |
entities | optional | Text entities для text. |
message_thread_id | optional | Відправка в topic/forum thread. |
comments_meta | optional | Shortcut для send_comment: discussion_chat_id, message_thread_id, опц. comment_count. |
reply_to, reply_to_message_id | optional | Reply на повідомлення. Для reply в інший чат передай reply_to як об'єкт з chat_id/message_id або replyToChatId/replyToMsgId. |
reply_markup | optional | TDLib reply markup payload. Для media_items/sendMessageAlbum не підтримується. |
options | optional | Сирий messageSendOptions. |
disable_notification, protect_content, from_background | optional | Alias-и для messageSendOptions. |
allow_paid_broadcast, paid_message_star_count | optional | Платні опції відправки, якщо TDLib/чат їх підтримує. |
update_order_of_installed_sticker_sets | optional | Прокидається в messageSendOptions як у звичайному sendMessage. |
schedule_date, send_when_online | optional | Планована відправка. |
effect_id, message_effect_id | optional | Ефект повідомлення, якщо TDLib/чат це підтримує. |
sending_id, only_preview | optional | Додаткові прапори/ідентифікатори з messageSendOptions. |
direct_messages_chat_topic_id, suggested_post_info | optional | Специфічні поля TDLib для direct messages / suggested posts. |
send_large_photos | optional | Shortcut прапор, який бекенд кладе в options для відправки великих фото. |
media | optional | Об'єкт cloud media payload. Також можна передати масив як alias для альбому, але рекомендований формат для нього - media_items. |
media_items | optional | Масив із 2-10 елементів для sendMessageAlbum. Елемент може бути cloud media payload або {"type":"forward","from_chat_id":"...","message_id":"..."}. |
media_type | optional | Можна передати окремо, якщо в media.type або елементах media_items[].type його нема. |
Загальні поля media
| Поле | Для яких типів | Примітка |
|---|---|---|
type | all | document, photo, video, audio, voice_note, video_note |
key | all | Cloud key із create_tg_media_upload_url. required |
file_name / filename | all | Ім'я файлу, яке піде в original_path. |
expected_size / size | all | Очікуваний розмір для TDLib generation. |
caption, caption_entities | document/photo/video/audio/voice_note | Caption у самому media payload. |
self_destruct_type | photo/video/voice_note/video_note | TTL/self-destruct timer. |
thumbnail | document/photo/video/video_note | Окремий cloud object для preview. |
Параметри по типах
document
| Поле | Тип | Що робить |
|---|---|---|
thumbnail | object | Preview для документа. |
disable_content_type_detection | bool | Вимикає авто-детекцію MIME типу в Telegram. |
photo
| Поле | Тип | Що робить |
|---|---|---|
width, height | int | Розміри фото. |
added_sticker_file_ids | array | Стікери, прикріплені до фото. |
show_caption_above_media | bool | Підпис над фото. |
has_spoiler | bool | Спойлер-ефект. |
video
| Поле | Тип | Що робить |
|---|---|---|
thumbnail | object | Preview thumbnail. |
cover | object | Cover image для відео. |
duration | int | Тривалість у секундах. |
width, height | int | Розміри відео. |
start_timestamp | int | З якого місця стартує прев'ю/відтворення. |
supports_streaming | bool | Streaming-friendly video. |
show_caption_above_media | bool | Підпис над відео. |
has_spoiler | bool | Спойлер-ефект. |
audio
| Поле | Тип | Що робить |
|---|---|---|
duration | int | Тривалість. |
title | string | Назва треку. |
performer | string | Виконавець. |
album_cover_thumbnail | object | Обкладинка. |
voice_note
| Поле | Тип | Що робить |
|---|---|---|
duration | int | Тривалість. |
waveform | base64 / list / bytes | Хвиля голосового. Необов'язково. |
caption | string | Підпис для voice note. |
Для native вигляду Telegram очікує голосове у форматі OGG/Opus. Якщо дати, наприклад,
mp3 або m4a, результат може поводитися як звичайний audio file.
video_note
| Поле | Тип | Що робить |
|---|---|---|
duration | int | Тривалість. |
length | int | Діаметр/розмір відеокружечка. required |
thumbnail | object | Preview thumbnail. |
Для video_note бажано відправляти квадратне mp4, інакше Telegram може
обрізати/відобразити не так, як очікується.
Приклади payload-ів
Document
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"text": "PDF",
"media": {
"type": "document",
"key": "tg/outgoing/userbot_1/chat_123/document/report.pdf",
"file_name": "report.pdf",
"expected_size": 456789,
"disable_content_type_detection": false
}
}
Photo
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"media": {
"type": "photo",
"key": "tg/outgoing/userbot_1/chat_123/photo/image.jpg",
"file_name": "image.jpg",
"width": 1200,
"height": 900,
"show_caption_above_media": true,
"has_spoiler": false,
"caption": "Фото"
}
}
Video
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"text": "ось відео",
"media": {
"type": "video",
"key": "tg/outgoing/userbot_1/chat_123/video/clip.mp4",
"file_name": "clip.mp4",
"expected_size": 1234567,
"duration": 17,
"width": 1920,
"height": 1080,
"supports_streaming": true,
"show_caption_above_media": true,
"has_spoiler": true
}
}
Audio
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"media": {
"type": "audio",
"key": "tg/outgoing/userbot_1/chat_123/audio/song.mp3",
"file_name": "song.mp3",
"duration": 198,
"title": "Song title",
"performer": "Artist"
}
}
Voice Note
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"media": {
"type": "voice_note",
"key": "tg/outgoing/userbot_1/chat_123/voice_note/voice.ogg",
"file_name": "voice.ogg",
"duration": 8
}
}
Video Note
{
"action": "send_message",
"userbot_id": 1,
"chat_id": "123",
"media": {
"type": "video_note",
"key": "tg/outgoing/userbot_1/chat_123/video_note/circle.mp4",
"file_name": "circle.mp4",
"duration": 12,
"length": 384
}
}
Що відбувається всередині
send_message/send_commentбудуєinputFileGeneratedзconversion=cloud_fetch_v1:...- TDLib запускає
updateFileGenerationStart - Бекенд дістає з
conversioncloud key - Генерує свіжий
presigned GET URLпо key - Качає файл у
destination_pathабо черезwriteGeneratedFilePart - Завершує generation через
finishFileGeneration
Це зроблено спеціально для того, щоб не передавати в Telegram тимчасовий GET URL, який може протухнути до моменту реальної відправки.
Типові помилки
| Симптом | Причина | Що перевірити |
|---|---|---|
create_tg_media_upload_url_error | Немає userbot_id або битий payload | Перевірити обов'язкові поля запиту. |
403 SignatureDoesNotMatch на PUT | Content-Type не збігся з підписом | Використовувати result.content_type із відповіді на створення upload URL. |
send_message_error / send_comment_error: media.key is required | Не переданий cloud key | Перевірити media.key. |
send_message_error / send_comment_error: Unsupported media.type | Непідтримуваний тип | Використовувати лише задокументовані значення. |
send_comment_error: message_thread_id is required | Не переданий thread comments | Передати comments_meta.message_thread_id або top-level message_thread_id. |
| Voice відправився як файл/audio | Невірний формат голосового | Для native voice використовувати .ogg/Opus. |
| Video note виглядає не як кружечок | Немає length або невідповідний media format | Передати length і квадратне mp4. |
| Upload пройшов, але TDLib не відправив файл | Об'єкт відсутній за key або listener не обробив generation | Перевірити storage object, listener logs і updateFileGenerationStart. |
Швидка перевірка в Postman
- WS connect до
/ws/chats/ - Надіслати
{"action":"open_client","userbot_id":1} - Надіслати
create_tg_media_upload_url - Зробити HTTP
PUTbinary уupload_url - Надіслати
send_messageабоsend_commentзmedia.key - Очікувати
send_message/send_comment,updateNewMessage,updateMessageSendSucceeded