Почему три шага
Тело HTTP на gateway ограничено 2 МиБ. Файл кладётся напрямую в объектное хранилище по короткоживущему URL. Gateway потом перечитывает объект, проверяет размер и MIME, гоняет антивирус и только тогда помечает вложение ready.
Короткий путь в SDK
const file = await client.attachments.upload({
channel: "custom:shop",
filename: "invoice.pdf",
mimeType: "application/pdf",
content: bytes, // Blob | Uint8Array | ArrayBuffer
});
await client.ingest.send({
channel: "custom:shop",
body: "Счёт",
attachment_ids: [file.id],
});Для ответа оператора тот же id в conversations.reply(..., { attachment_ids: [file.id] }).
Передавайте настоящий MIME-тип. image/jpeg, image/png, image/webp и image/avif отображаются как изображения; всё, что не является безопасным изображением, показывается как документ с именем и размером. Медиа-группа — это несколько attachment_ids в одном сообщении, а не архив и не набор ссылок.
Шаги вручную
POST /v1/attachments/intent—filename,mime_type,size_bytes,channel(для API-ключа обязателен). Ответ:attachment_id,upload_url, заголовки для PUT.PUT upload_urlс теми же заголовками. ЛишнийContent-Typeломает подпись S3.POST /v1/attachments/{id}/complete— ready или ошибка (attachment_type_blocked,attachment_infected, size mismatch).
Скачать
GET /v1/attachments/{id} — метаданные, download_url когда ready. GET …/download — редирект на presigned GET. SDK: client.attachments.get / download.
Надёжность и безопасность
- Не делайте S3 bucket публичным и не сохраняйте presigned URL надолго.
- Не подставляйте имя файла или MIME из пользовательского HTML без экранирования.
- Считайте загрузку завершённой только после успешного
complete. - Если complete отклонён, не отправляйте сообщение с этим id и покажите оператору причину.
Пустой файл
SDK отклоняет 0 байт до intent. Сообщение без текста допустимо, только если есть attachment_ids.