Перейти к содержанию

Загрузка файлов

Как загрузить видео, фото и аудио в Slicer через API — одноразовая ссылка для curl -T, файл целиком, по частям или импорт по публичному адресу.

На этой странице

Монтаж собирается из загруженных материалов: видео, фото и аудио. Любой файл сначала становится загрузкой — у неё есть id, статус и сведения о медиа. Готовые загрузки (status: ready) передаются в uploadIds при создании проекта.

Четыре способа

Способ Когда удобен Токен при отправке файла
Одноразовая ссылка uploadUrlпроще всего; файл отправляет другая программа или ИИ-агентне нужен
Файл целикомфайл у вашего сервиса, загрузка одним запросомнужен
По частямбольшие файлы и нестабильная сеть: части параллельно, повтор частинужен
Импорт по адресуфайл уже лежит по публичному https-адресуне нужен — файл скачает Slicer

Создать загрузку

Для первых трёх способов загрузка создаётся заранее — сервер должен знать имя и размер файла:

Терминал
curl https://api.slicer.media/v1/uploads \
  -H "Authorization: Bearer $SLICER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"interview.mp4","size":48211337}'
Ответ
{
  "ok": true,
  "data": {
    "upload": {
      "id": "7d0c6a4e-2f7b-4f5e-9a0e-3b8f2c1d9e61",
      "fileName": "interview.mp4",
      "purpose": "source",
      "origin": "client",
      "sizeBytes": 48211337,
      "status": "uploading",
      "partSize": 8388608,
      "partCount": 6,
      "uploadedParts": [],
      "progress": null,
      "media": null,
      "error": null,
      "createdAt": "2026-10-16T09:12:04.000Z"
    },
    "uploadUrl": "https://api.slicer.media/v1/upload-links/slc_ul_…",
    "uploadUrlExpiresAt": "2026-10-16T10:12:04.000Z"
  }
}
  • fileName — с расширением: по нему определяется вид материала (видео, фото или аудио).
  • size — точный размер файла в байтах.
  • purpose — назначение; для материалов монтажа — source (по умолчанию).

Одноразовая ссылка

uploadUrl принимает PUT всего файла без токена — разрешение заключено в самой ссылке:

Терминал
curl -T interview.mp4 "$UPLOAD_URL"

Свойства ссылки:

  • одна попытка — ссылка гаснет при первом запросе, даже если он оборвался; для повтора создайте новую загрузку или отправьте на ту же загрузку файл целиком с токеном (ниже);
  • не дольше часа — время окончания в uploadUrlExpiresAt;
  • только запись — по ссылке нельзя ничего прочитать или узнать об аккаунте;
  • размер тела должен совпадать с заявленным size, заголовок Content-Length обязателен (curl -T ставит его сам).

После приёма файла загрузка завершается сама, ответ — объект загрузки. Ссылку удобно передать ИИ-агенту или скрипту на другой машине, не раскрывая токен.

Файл целиком

Тот же приём, но с токеном и на постоянный адрес загрузки:

Терминал
curl -X PUT "https://api.slicer.media/v1/uploads/$UPLOAD_ID/content" \
  -H "Authorization: Bearer $SLICER_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @interview.mp4

Сервер сам режет поток на части, шифрует их и завершает загрузку. Content-Length должен быть равен заявленному размеру.

По частям

Для больших файлов: части по partSize байт (8 МиБ), нумерация с 1, последняя — остаток. Части можно отправлять параллельно и повторять — уже принятые перечислены в uploadedParts. Когда все части на месте, вызовите complete.

JavaScript
Python
upload-parts.mjs
// Node.js 20+: node upload-parts.mjs video.mp4
import { open, stat } from 'node:fs/promises';
import { basename } from 'node:path';

const API = 'https://api.slicer.media/v1';
const auth = { Authorization: `Bearer ${process.env.SLICER_TOKEN}` };
const file = process.argv[2];

async function call(method, path, body, headers = {}) {
  const response = await fetch(`${API}${path}`, { method, headers: { ...auth, ...headers }, body });
  const json = await response.json();
  if (!json.ok) throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
  return json.data;
}

const { size } = await stat(file);
const { upload } = await call('POST', '/uploads', JSON.stringify({ fileName: basename(file), size }), {
  'Content-Type': 'application/json',
});

const handle = await open(file);
const queue = Array.from({ length: upload.partCount }, (_, i) => i + 1);

async function worker() {
  for (let part = queue.shift(); part != null; part = queue.shift()) {
    const offset = (part - 1) * upload.partSize;
    const length = Math.min(upload.partSize, size - offset);
    const { buffer } = await handle.read(Buffer.alloc(length), 0, length, offset);
    for (let attempt = 1; ; attempt += 1) {
      try {
        await call('PUT', `/uploads/${upload.id}/parts/${part}`, buffer, { 'Content-Type': 'application/octet-stream' });
        break;
      } catch (error) {
        if (attempt === 3) throw error;
      }
    }
  }
}

await Promise.all(Array.from({ length: 4 }, worker)); // 4 части одновременно
await handle.close();
const ready = await call('POST', `/uploads/${upload.id}/complete`);
console.log(ready.status, ready.media);

Части считаются в отдельной корзине лимита — 1200 запросов в минуту (Лимиты). Начатую по частям загрузку нельзя продолжить целиком (409 upload_in_parts) — продолжайте частями.

Импорт по адресу

Если файл уже лежит в интернете, Slicer скачает его сам:

Терминал
curl https://api.slicer.media/v1/uploads/import \
  -H "Authorization: Bearer $SLICER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://media.example.com/clips/product-demo.mp4"}'
  • Только https и только публичные адреса: адреса внутренних сетей не принимаются, каждое перенаправление проверяется заново.
  • Имя файла берётся из адреса. Если в адресе нет расширения (…/download?id=42), передайте fileName: "fileName": "product-demo.mp4".
  • Импорт идёт в фоне: загрузка сразу приходит со статусом uploading, поле progress показывает долю скачанного (0–1). Затем — processing и ready или failed с причиной в error.
  • Одновременно — до 3 импортов на аккаунт, скачивание — до 30 минут. Ограничения размера и формата — те же, что у обычной загрузки.

Ссылки на страницы видеохостингов (не на сам файл) не подходят: нужен прямой адрес файла.

Статусы загрузки

Статус Что происходит
uploadingждём файл или части; у импорта — скачиваем
processingфайл получен, сервер проверяет формат и готовит обложку
readyможно использовать в монтаже; сведения о файле — в media
failedфайл не принят; причина — в error
abortedзагрузка отменена (DELETE /v1/uploads/{id})

Узнать статус — GET /v1/uploads/{id} или вебхуки upload.ready и upload.failed. Поле media готовой загрузки: kind (video, image, audio), durationSec, width, height, hasAudio.

Форматы и ограничения

Ограничения те же, что в приложении, и приходят в каталоге GET /v1/styles → materialLimits:

  • видео — mp4, mov, m4v, webm, mkv, avi; фото — jpg, jpeg, png, webp; аудио — mp3, m4a, aac, wav, ogg, opus, flac;
  • до 20 материалов в проекте, из них видео, фото и аудио — каждого вида в своих пределах;
  • формат проверяется не только по расширению, но и по содержимому файла.

Подробнее о размерах, длительности и разрешении — Форматы и ограничения файлов. Незавершённые загрузки удаляются через сутки, исходники проекта хранятся 7 дней после монтажа (sourcesAvailable в проекте), готовые ролики — пока вы их не удалите.

Ошибки загрузки

Код Статус Причина
unsupported_format400расширение или содержимое файла не поддерживается
file_too_large400файл больше допустимого для своего вида
empty_file400файл пустой
not_a_video, not_an_image, not_audio, media_unreadable400содержимое не совпадает с расширением или файл повреждён
resolution_too_low, resolution_too_high, image_too_large400разрешение вне допустимых пределов
audio_too_long400аудио длиннее допустимого
too_many_uploads, daily_upload_limit400много незавершённых загрузок или исчерпан суточный объём
bad_part, bad_part_size400неверный номер или размер части
parts_missing400complete вызван до отправки всех частей
length_required411нет заголовка Content-Length
bad_content_length, body_too_short, body_too_long400размер тела не совпадает с заявленным size
upload_not_active409загрузка уже завершена или отменена
upload_in_parts409загрузка уже идёт по частям
link_not_found404ссылка на загрузку не найдена
link_expired, link_used410срок ссылки истёк или она уже использована
bad_url, file_name_required400адрес импорта не https или в нём нет имени файла
too_many_imports429уже идут 3 импорта — дождитесь окончания

Что дальше