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

> Загрузите файл до 95 МБ одним запросом. Для файлов до 2 ГБ используйте загрузку по частям с продолжением после обрыва связи.

Canonical: https://transcript1.com/ru/docs/uploads
Language: ru
Last updated: 2026-10-14

Из загруженных аудио- и видеофайлов получаем текст через распознавание речи с помощью ИИ. Для файла можно указать только `source=auto` или `source=stt`. Язык и определение говорящих настраиваются через `language` и `diarize` — см. [«Источники и параметры»](https://transcript1.com/ru/docs/sources-and-options).

## Форматы и размер файлов

Проверьте расширение файла: подойдут `mp3`, `wav`, `m4a`, `flac`, `ogg`, `opus`, `mp4`, `mov`, `webm` и `mkv`. С другим расширением API вернёт `422 unsupported_media`. Внутри обязательно должна быть аудиодорожка, иначе задача тоже завершится с `unsupported_media`.

| Способ загрузки или лимит | Значение |
|---|---|
| Загрузка одним запросом (`multipart/form-data`) | 95 МБ |
| Загрузка по частям | До 2 ГБ (2 000 000 000 байт), если тариф не задаёт меньший лимит |
| Одновременно открытых загрузок по частям на команду | 20 |

Если файл слишком большой, API ответит `413 media_too_large`. Допустимый размер в байтах будет в поле `max_bytes`.

## Загрузка одним запросом

Файл до 95 МБ отправьте в `POST /v1/transcriptions` как `multipart/form-data`, в поле `file`. При необходимости добавьте поля формы `language`, `diarize` (`true` или `false`), `source` (`auto` или `stt`) и `webhook_url`:

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions?wait=60" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -F file=@interview.m4a \
  -F language=en \
  -F diarize=true
```

API вернёт объект транскрибации с `source.platform=upload`. Как и для видео по ссылке, HTTP-код `202` означает, что обработка ещё идёт, а `200` — что задача завершилась. При отправке пустого файла вы получите `422 invalid_request`.

## Загрузка по частям

Разбейте большой файл на части по плану сервера. Тогда после обрыва связи не придётся отправлять всё заново. Загрузка состоит из четырёх шагов.

### 1. Запросите план загрузки

Отправьте JSON с именем и размером файла; `mime_type` можно не указывать. Передайте `Idempotency-Key`, чтобы при повторном запросе не создать вторую задачу:

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Idempotency-Key: interview-2026-10-13" \
  -H "Content-Type: application/json" \
  -d '{"upload":{"filename":"interview.m4a","size":48210334,"mime_type":"audio/mp4"},"language":"auto","diarize":true}'
```

Вы получите HTTP-код `201`, статус задачи `awaiting_upload` и план в блоке `upload`:

```json
{
  "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
  "object": "transcription",
  "status": "awaiting_upload",
  "upload": {
    "chunk_url_template": "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/{index}",
    "headers": { "X-Upload-Token": "t1u_..." },
    "expires_at": "2026-10-13T10:30:00.000Z",
    "chunks": [
      { "index": 0, "offset": 0, "size": 8388608 },
      { "index": 1, "offset": 8388608, "size": 8388608 }
    ]
  }
}
```

Сервер рассчитывает части примерно по 8 МиБ (8 388 608 байт). Их список находится в `chunks`; выше показана только его часть. Для отправки байтов нужен секретный токен `X-Upload-Token`. Он относится только к этой загрузке и действует 1 час — до `expires_at`.

### 2. Загрузите части файла

Для каждой части подставьте её `index` вместо `{index}` в `chunk_url_template` и выполните `PUT`. Из файла возьмите ровно `size` байт, начиная с `offset`. Передайте их в теле запроса с `Content-Type: application/octet-stream`. В заголовках достаточно `X-Upload-Token`, обычный `Authorization` здесь не нужен.

```bash
curl -X PUT "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/0" \
  -H "X-Upload-Token: t1u_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @chunk-0.bin
```

После успешного `PUT` ответ выглядит так: `{ "object": "upload_chunk", "index": 0, "size": 8388608 }`. Часть можно отправить повторно — она заменит предыдущую. Если размер не совпадает с планом или в плане нет такого индекса, API вернёт `422 invalid_request`. Если токен отсутствует или истёк, вернётся `401 unauthorized`.

### 3. Продолжите после обрыва связи

Чтобы узнать, какие части дошли до сервера, вызовите `GET /v1/transcriptions/:id/upload`:

```json
{
  "object": "upload",
  "status": "awaiting_upload",
  "total_bytes": 48210334,
  "uploaded_bytes": 16777216,
  "received_chunks": [0, 1],
  "chunks": [ { "index": 0, "offset": 0, "size": 8388608 } ],
  "expires_at": "2026-10-13T10:30:00.000Z"
}
```

Дозагрузите части, чьих индексов нет в `received_chunks`. Если срок токена закончился, снова выполните запрос из шага 1. Не меняйте `Idempotency-Key` и параметры: так вы получите ту же задачу с новым токеном, а не создадите другую.

### 4. Завершите загрузку

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/complete" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
```

Вызов `POST /v1/transcriptions/:id/upload/complete` проверит наличие и размер всех частей, соберёт файл и поставит транскрибацию в очередь. В ответе придёт `202` с объектом задачи.

Если чего-то не хватает, API вернёт `409 upload_incomplete`. Поле `missing_chunks` перечислит индексы частей, которые нужно отправить ещё раз. Если загрузку уже завершили или отменили, вернётся `409 invalid_state`. После успешного завершения проверяйте статус через `GET /v1/transcriptions/:id?wait=60` или ждите [вебхук](https://transcript1.com/ru/docs/webhooks).

### Полный пример на Python

```python
import os
import requests

API = "https://api.transcript1.com"
auth = {"Authorization": f"Bearer {os.environ['TRANSCRIPT1_API_KEY']}"}
path = "interview.m4a"

created = requests.post(
    f"{API}/v1/transcriptions",
    headers={**auth, "Idempotency-Key": "interview-2026-10-13"},
    json={"upload": {"filename": os.path.basename(path), "size": os.path.getsize(path)}},
)
created.raise_for_status()
transcription = created.json()
upload = transcription["upload"]

with open(path, "rb") as file:
    for chunk in upload["chunks"]:
        file.seek(chunk["offset"])
        url = upload["chunk_url_template"].replace("{index}", str(chunk["index"]))
        response = requests.put(
            url,
            data=file.read(chunk["size"]),
            headers={**upload["headers"], "Content-Type": "application/octet-stream"},
        )
        response.raise_for_status()

done = requests.post(f"{API}/v1/transcriptions/{transcription['id']}/upload/complete", headers=auth)
done.raise_for_status()
print(done.json()["status"])
```

## Ограничения и сроки хранения

- Команда может держать открытыми до 20 загрузок со статусом `awaiting_upload`. При превышении API вернёт `429 too_many_active_jobs` и заголовок `Retry-After`.
- На завершение загрузки есть 24 часа с момента создания. После этого отменяем её и удаляем загруженные части.
- Аудио- и видеофайлы удаляем через 24 часа после перехода задачи в `completed`, `failed` или `canceled`. Транскрипт остаётся, пока вы сами не удалите его через `DELETE /v1/transcriptions/:id`.
- Когда длительность файла станет известна, спишем минуты с округлением вверх. Если транскрибация завершится с ошибкой или вы её отмените, платить не нужно. Подробнее — в разделе [«Тарифы и лимиты»](https://transcript1.com/ru/docs/billing-and-limits).
