← Все статьи
Руководство

Медиа-вложения Telegram в едином Webhook: фото, голос, документы, контакты и геолокация

Официальный Telegram Bot API представляет медиа как Telegram-specific поля объекта Message: photo, document, voice, contact, location и другие. Если путь приема у вас построен на едином webhook UnifyPort, не нужно напрямую переносить каждое поле Telegram в основную модель inbox. Сначала сохраните envelope message.received: текст читайте из data.message.text, медиа — из data.message.attachments[], контакт — из data.message.contact, координаты — из data.message.location.

Ключевые выводы

  • Telegram media message — это не просто «сообщение с текстом»: официальный Telegram Bot API описывает отдельные optional fields для фотографий, документов, голосовых сообщений, контактов и геолокации.
  • UnifyPort нормализует входящий Telegram content в тот же message.received envelope, который используется для WhatsApp, LINE, TikTok, Zalo и X.
  • Медиафайлы находятся в data.message.attachments[]; у вложений есть поля вроде type, url, mimetype и optional metadata по размеру или длительности.
  • Проверяйте X-Device-Signature по raw request body до чтения содержимого, скачивания файлов или передачи события в CRM/AI workflow.
  • Если вы еще выбираете между Telegram Bot API webhook и единым inbound webhook, начните со сравнения Telegram Bot API Webhook или единый inbound webhook.

Что отправляет Telegram и что должен хранить inbox

Объект Message в Telegram Bot API удобен для Telegram bot: код ветвится по полям Telegram и работает внутри одной platform model. Shared support inbox обычно решает другую задачу. Он должен принимать Telegram сегодня, а завтра — WhatsApp, LINE, Zalo, TikTok или X, не переписывая storage contract под каждый provider.

Поэтому первой production-записью лучше делать стандартный event envelope UnifyPort, описанный в Standard event types and payload:

{
  "id": "evt_b1a7c3e5f8",
  "type": "message.received",
  "provider": "telegram",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-06-08T12:37:00Z",
  "data": {
    "conversation": { "id": "5005", "type": "user" },
    "sender": { "id": "4004", "type": "user", "name": "Jordan Lee" },
    "message": {
      "id": "3003",
      "direction": "inbound",
      "sent_at": "2026-06-08T12:37:00Z",
      "contact": {
        "phone_number": "+8600000000000",
        "first_name": "Demo",
        "last_name": "User",
        "vcard": "BEGIN:VCARD\nVERSION:3.0\nFN:Demo User\nEND:VCARD",
        "user_id": 4004
      }
    },
    "event": { "kind": "message_received" }
  }
}

Фотографии, voice notes, видео и документы попадают в data.message.attachments[]. Общий контакт находится в data.message.contact. Геолокация хранится в data.message.location с longitude и latitude.

Карта хранения для Telegram media

Входящий контентПоле UnifyPortКомментарий
Текст или captiondata.message.textУ media message может не быть текста. Не делайте это поле обязательным.
Фото, аудио, видео, документ, файлdata.message.attachments[]Каждый элемент содержит нормализованный type; media URL может быть временным, поэтому обрабатывайте или копируйте его по вашим retention rules.
Длительность voice/audioattachments[].duration_ms, если естьСчитайте поле optional.
Название документаattachments[].title, если естьПолезно для UI, но не подходит как unique identifier.
Общий контактdata.message.contactTelegram contact payload может содержать телефон, имя, vCard и user id.
Геолокацияdata.message.locationХраните { longitude, latitude } отдельно от свободного текстового адреса.
Идентификатор сообщенияdata.message.idИспользуйте для message-level действий; для дедупликации webhook delivery используйте top-level id.

Этот материал — практическое продолжение чеклиста inbound-интеграции с Webhook. Сначала создайте receiver, сохраните нормализованное событие, а затем отправляйте вложения в search index, CRM, AI triage или media worker.

Сначала подпись, потом JSON parsing

Документация доставки UnifyPort описывает headers X-Device-Timestamp и X-Device-Signature. Когда для endpoint включен signing_secret, подпись — это hex HMAC-SHA256 от строки:

<X-Device-Timestamp>.<raw request body>

Официальная документация Node.js описывает crypto.createHmac() и crypto.timingSafeEqual(), а Express documentation указывает, что express.raw() разбирает payload в Buffer. Поэтому receiver должен проверить raw body до JSON parsing.

import crypto from 'node:crypto';
import express from 'express';

const app = express();
const signingSecret = process.env.WEBHOOK_SIGNING_SECRET;

if (!signingSecret) throw new Error('WEBHOOK_SIGNING_SECRET is required');

app.post('/webhooks/unifyport', express.raw({ type: 'application/json' }), async (req, res) => {
  const timestamp = req.get('X-Device-Timestamp') ?? '';
  const signature = req.get('X-Device-Signature') ?? '';

  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(timestamp + '.')
    .update(req.body)
    .digest();

  const supplied = /^[0-9a-f]{64}$/i.test(signature)
    ? Buffer.from(signature, 'hex')
    : Buffer.alloc(0);

  if (supplied.length !== expected.length || !crypto.timingSafeEqual(supplied, expected)) {
    return res.sendStatus(401);
  }

  const event = JSON.parse(req.body.toString('utf8'));
  await storeEvent(event.id, event);

  if (event.type !== 'message.received' || event.provider !== 'telegram') {
    return res.sendStatus(202);
  }

  const message = event.data.message;
  for (const attachment of message.attachments ?? []) {
    await mediaQueue.enqueue({
      eventId: event.id,
      messageId: message.id,
      conversationId: event.data.conversation.id,
      type: attachment.type,
      url: attachment.url,
      mimetype: attachment.mimetype,
      title: attachment.title,
      durationMs: attachment.duration_ms,
    });
  }

  if (message.contact) await contactQueue.enqueue(message.contact);
  if (message.location) await geoQueue.enqueue(message.location);

  return res.sendStatus(202);
});

В production замените sample queues на вашу базу данных или очередь задач. Главная граница: verified event должен быть надежно сохранен до медленных скачиваний, OCR, AI enrichment или CRM sync. Более глубокие детали подписи, повторных доставок и acknowledgement описаны в Webhook delivery and signature verification. Если кроме медиа вы обрабатываете реакции, рядом стоит прочитать руководство по message.reaction.

Где встраивается UnifyPort

UnifyPort предоставляет неофициальный интерфейс для входящих Telegram messages из подключенного messaging account и доставляет их как нормализованные events. Вы по-прежнему решаете, как долго хранить медиа, нужно ли копировать временные file URLs и какие internal workers могут получать доступ к вложениям.

Главная выгода — повторное использование schema. Тот же receiver, который сегодня принимает Telegram photos, позже может принять WhatsApp images, LINE photos, Zalo messages, TikTok DMs или X messages без превращения Telegram Message object в центр вашей базы данных.

Ограничения и компромиссы

Используйте официальный Bot API, если вы строите Telegram bot identity, bot commands, inline keyboards, BotFather configuration или Telegram-specific bot behavior. Единый webhook лучше подходит для inbound intake существующего messaging account или cross-channel queue.

Также не предполагаюте, что каждый provider поддерживает все media shapes Telegram. Storage layer можно нормализовать, но provider-specific capability checks должны оставаться на краях системы.

FAQ

Telegram photos хранятся в data.message.text?

Нет. Текст и caption находятся в data.message.text; медиафайлы находятся в data.message.attachments[] с нормализованным type.

Может ли один webhook принимать Telegram contacts и locations?

Да. Событие message.received может содержать structured fields вроде data.message.contact или data.message.location, если входящее сообщение включает такой контент.

Нужно ли скачать медиа до ответа 2xx?

Обычно нет. Сначала сохраните verified event, поставьте media processing в очередь и верните 2xx. Медленные скачивания не должны блокировать acknowledgement.

Это то же самое, что Telegram Bot API webhook?

Нет. Telegram Bot API webhook принимает Telegram Update objects для bot token. UnifyPort webhook принимает нормализованные events для подключенного messaging account и может использовать один receiver для разных providers.

Следующий шаг

Откройте Create webhook endpoint, подпишитесь на message.received, включите signing_secret и протестируйте текст, вложения, контакт и геолокацию до подключения handler к production workflow.

Sources checked on 2026-09-08

UnifyPort API

Превратите интеграцию сообщений в стабильный продуктовый pipeline.

Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.