Отправка медиа через UnifyPort: проверка URL и доставки
Для отправки изображения, видео, аудио или документа через UnifyPort используйте POST /v1/messages, поддерживаемый message.type и хотя бы один непустой источник: message.url, message.file_url или message.file_key. URL должен быть абсолютным HTTP(S)-адресом. Имя локального файла не является доступным URL, а ответ со status: accepted не подтверждает получение файла адресатом.
Главное
- Проверяйте поддержку формата для канала выбранного аккаунта обмена сообщениями.
- Начните с одного явно заданного доступного URL; не угадывайте приоритет нескольких источников.
- Исходящий объект
messageотличается от входящегоdata.message.attachments[]. - Проверяйте доступ к файлу, валидацию запроса, подключение аккаунта и доставку отдельно.
Сначала выберите контракт отправки
Неофициальный интерфейс UnifyPort использует контракт отправки медиа. Это не Telegram Bot API и не LINE Messaging API. Например, документация Telegram по отправке файлов описывает идентификаторы файлов, HTTP URL и multipart-загрузку для собственных методов. Из этого не следует, что UnifyPort принимает Telegram file_id в качестве file_key или поддерживает тот же запрос загрузки.
| Поле | Что установлено документацией UnifyPort |
|---|---|
message.type | Типы включают image, video, audio, document, file; поддержку канала нужно проверять отдельно |
message.url или message.file_url | Непустой абсолютный HTTP(S) URL источника |
message.file_key | Документированная альтернатива, но не основание придумывать ключ или endpoint загрузки |
message.caption | Необязательная подпись для изображения, видео, документа и файла |
provider_data.seconds | Необязательная длительность аудио и видео WhatsApp: неотрицательное целое число секунд |
Для видео WhatsApp допустим диапазон длительности 0–4294967295. provider_data.waveform предназначен только для аудио. Не копируйте входящее значение duration_ms в поле секунд без преобразования. Если длительность не нужна, не передавайте её вместо угадывания значения.
Текущая матрица поддержки сообщений не предусматривает отправку аудио и документов/файлов в TikTok, отмечает аудио X как частично поддерживаемое и разделяет whatsapp-protocol и whatsapp. Общий endpoint не гарантирует одинаковых возможностей и ограничений для всех каналов.
Подготовьте файл до формирования запроса
Это рекомендации по архитектуре приложения, а не дополнительные гарантии платформы:
- Убедитесь, что оператор вправе отправлять сообщения через выбранный аккаунт в выбранный диалог. Для группы используйте ID и тип диалога, а не ID автора сообщения.
- Проверьте авторизацию и
runtime_statusотдельно: авторизованный аккаунт не обязательно подключён. - Разместите нужный файл в контролируемом доступном источнике. Страница, открывающаяся после входа в браузере, не доказывает, что отправляющий сервис получит файл.
- Проверьте получение из отдельного серверного окружения без браузерных cookie. Убедитесь, что ответ содержит нужные медиа, а не HTML-страницу входа или ошибки.
- Если URL имеет срок действия, учитывайте ожидаемое время в очереди и последующее получение. Контракт не обещает единого предельного срока скачивания; успешная предварительная проверка не гарантирует доступность позже.
Предпочитайте HTTPS, минимально необходимый доступ и одобренное приложением хранилище. Не записывайте подписанные параметры URL и секреты в обычные логи. Это рекомендации по безопасности, а не утверждения о недокументированных сетевых фильтрах UnifyPort.
Сформируйте запрос с URL
Эта JavaScript-функция создаёт тело запроса из выбранного аккаунта, диалога и разрешённого URL. Она не загружает файл и не проверяет его доступность по сети. До вызова проверьте права оператора и поддержку канала.
function buildMediaRequest({ accountId, conversation, type, url, caption }) {
const types = new Set(['image', 'video', 'audio', 'document', 'file']);
if (!accountId || !conversation?.id || !conversation?.type) {
throw new Error('Account and conversation are required');
}
if (!types.has(type)) throw new Error('Unsupported media type');
const source = new URL(url);
if (!['http:', 'https:'].includes(source.protocol) ||
source.username || source.password) {
throw new Error('Use an approved HTTP(S) media source');
}
const message = { type, url: source.href };
if (caption !== undefined) {
if (type === 'audio' || typeof caption !== 'string') {
throw new Error('Caption is not valid for this request');
}
message.caption = caption;
}
return {
account_id: accountId,
to: { id: conversation.id, type: conversation.type },
message,
};
}
Отправьте полученный JSON в POST /v1/messages с серверной аутентификацией через X-Api-Key и Content-Type: application/json. Функция намеренно задаёт только message.url. Документация требует хотя бы один источник, но не определяет приоритет конфликтующих источников.
Не вставляйте входящий объект вложения непосредственно в тело отправки. В руководстве по входящим медиа описаны attachments[].type, url, mimetype и сопутствующие данные: это поля получения, а не полный исходящий запрос. Если исходная ссылка уже истекла, сначала определите подходящий способ восстановления по руководству по ссылкам на скачивание, а затем решайте вопрос пересылки.
Найдите этап сбоя
| Наблюдение | Что проверить | Чего избегать |
|---|---|---|
Передан локальный путь, относительный URL или data: URL | Подготовьте абсолютный HTTP(S) URL | Переименовывать путь в file_key |
| URL работает только в вашем браузере | Авторизацию, срок действия, перенаправления и реальные байты ответа | Считать, что браузерная сессия доступна отправителю |
unsupported_message_type | Канал и тип медиа | Повторять неизменный запрос |
provider_not_ready | Авторизацию и состояние подключения | Запускать повторную авторизацию без диагностики |
| Тайм-аут запроса | Сохраните исходящую операцию и разберите неопределённый результат | Автоматически отправлять ещё раз с риском дубля |
Ответ accepted | Сохраните идентификаторы; отдельно проверьте поддерживаемые подтверждения доставки | Сразу показывать «доставлено» или «прочитано» |
Справочник ошибок определяет машиночитаемые коды: используйте их, а не предположения по тексту сообщения. Сохраняйте request_id для диагностики, но не как токен дедупликации. Эту границу объясняет руководство по трассировке запросов.
При обработке подтверждений сверяйтесь со справочником событий и матрицей каналов. Проверяйте подпись webhook и учитывайте дубликаты и нарушение порядка событий. Не каждый канал выдаёт каждый вид подтверждения. Отсутствие подтверждения оставляет результат неизвестным, а не разрешает повторную отправку.
Приёмочные проверки и FAQ
До запуска предусмотрите тесты доступного файла, истёкшего URL, страницы входа вместо файла, неподдерживаемой пары канал/тип, отключённого аккаунта и потери ответа отправки. Здесь не заявляется, что эти проверки уже выполнены в реальной среде.
Можно ли напрямую загрузить локальный файл этим JSON-запросом?
Документированный запрос использует URL или файловый ключ. Статья не устанавливает наличие multipart-endpoint. Разместите файл через разрешённый процесс хранения и используйте доступный URL.
Можно ли передать Telegram file_id как file_key?
Такая совместимость не документирована. Не смешивайте нативные идентификаторы Telegram с полями источника UnifyPort.
Означает ли accepted, что получатель получил файл?
Нет. Это принятие запроса, а не подтверждение доставки или прочтения.
Следующий шаг и источники
Пройдите руководство по отправке изображений и файлов с одним разрешённым тестовым диалогом и одним одобренным источником медиа, прежде чем включать очередь или автоматическую отправку.
Источники проверены 2026-10-09:
Превратите интеграцию сообщений в стабильный продуктовый pipeline.
Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.