Загрузка файла
POST /transcriptions — загрузите аудио или видео (до 2 ГБ) на расшифровку одним HTTP-запросом и опрашивайте статус до completed.
POST /transcriptions
Загружает один аудио/видеофайл сырым телом запроса и запускает расшифровку. Отвечает сразу,
возвращая id расшифровки — дальше опрашивайте
Получение расшифровки, пока status не станет completed.
Нужно разрешение на загрузку
Эндпоинт доступен только ключам, созданным с включенной опцией Разрешить загрузку файлов. Существующие ключи — только для чтения: если ваш ключ старше этой функции, создайте новый. См. Аутентификация → Права ключа.
Формат запроса
Файл — это тело запроса. Без multipart-форм, без JSON-оберток, без протоколов чанков:
| Часть | Значение |
|---|---|
| Тело | Байты файла как есть (--data-binary в curl). |
| Authorization | Bearer mk_live_… (ключ с правом загрузки). |
| Content-Length | Обязателен. HTTP-клиенты ставят его сами для файловых тел; запрос без него отклоняется с кодом 411. |
| Content-Disposition | Обязателен: attachment; filename="meeting.mp3". Расширение определяет формат, имя становится названием расшифровки. |
| Idempotency-Key | Необязателен, но рекомендуем: уникальная строка на файл (например, UUID). Делает ретраи безопасными — см. Ретраи. |
Почему имя файла — в заголовке
В именах файлов часто есть персональные данные. Заголовки не попадают в логи URL — поэтому
?filename= не принимается. Для кириллицы используйте стандартную форму RFC 5987:
Content-Disposition: attachment; filename*=UTF-8''%D0%9F%D0%BB%D0%B0%D0%BD.mp3.
Query-параметры
Все необязательные:
| Параметр | Тип | Описание |
|---|---|---|
language | string | Язык речи. По умолчанию auto (определяется по аудио) — см. Поддерживаемые языки. |
project_id | UUID | Прикрепить расшифровку к проекту. UUID — из Списка проектов. |
diarize | boolean | Определять спикеров. По умолчанию true. |
speakers_count | integer | Число спикеров (1–20), если известно — улучшает диаризацию. |
ai_metadata | boolean | Генерировать AI-слой: саммари, название, имена спикеров, темы и дефолтные AI-отчеты. По умолчанию false — см. ниже. |
AI-анализ по умолчанию выключен для API-загрузок
С ai_metadata=false (по умолчанию) вы быстрее получаете полный текст: text с метками
спикеров, но summary и topics остаются null, prompt_results пуст, название — имя файла,
спикеры под генерик-метками. Передайте ai_metadata=true, если нужен тот же AI-слой, что
делает приложение. В обоих случаях расшифровка появляется в приложении, и AI-отчеты можно
сгенерировать там вручную позже. Списание минут одинаковое в обоих режимах.
Поддерживаемые языки
auto (по умолчанию — язык определяется по аудио) или один из:
en, es, ru, zh, hi, ar, pt, bn, fr, de, ja, ko, tr, it, vi, pl, uk, nl, id, th, fa, sv, cs, ro, el, hu, da, fi, no, sk, he, ms, bg, hr, sr, sl, lt, lv, et, ta, te, mr, ur, sw, ml, kn, gu, pa, my, ne, si, km, lo, az, kk, uz, ka, hy, sq, bs, mk, is, mn, tg, tk, tt, ca, eu, gl, cy, af, tl, jw, su, yo, ha, so, am, sn, mg, ln, mt, lb, oc, br, nn, fo, sd, ps, ht, mi, haw, yi, ba, be, as, bo, sa, la
Двухбуквенные коды ISO 639-1 (плюс haw и jw). Неподдерживаемое значение вернет 422.
Запрос
curl -X POST "https://app.memoai.tech/api/v1/developer/transcriptions?language=ru" \
-H "Authorization: Bearer mk_live_your_key_here" \
-H 'Content-Disposition: attachment; filename="standup.mp3"' \
--data-binary @standup.mp3import httpx
with open("standup.mp3", "rb") as f:
resp = httpx.post(
"https://app.memoai.tech/api/v1/developer/transcriptions",
params={"language": "ru"},
headers={
"Authorization": "Bearer mk_live_your_key_here",
"Content-Disposition": 'attachment; filename="standup.mp3"',
},
content=f, # стримится с диска — работает и для 2 ГБ
timeout=httpx.Timeout(10, write=None), # не обрывать долгую отправку
)
resp.raise_for_status()
t = resp.json()
print(t["uuid"], t["status"]) # "3fa85f64-…" "queued"import { openAsBlob } from "node:fs"; // Node 20+
const res = await fetch(
"https://app.memoai.tech/api/v1/developer/transcriptions?language=ru",
{
method: "POST",
headers: {
Authorization: "Bearer mk_live_your_key_here",
"Content-Disposition": 'attachment; filename="standup.mp3"',
},
body: await openAsBlob("standup.mp3"), // стрим, Content-Length выставится сам
},
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const t = await res.json();
console.log(t.uuid, t.status); // "3fa85f64-…" "queued"С подключенным локальным MCP-сервером просто попросите:
Загрузи ~/Записи/standup.mp3 в Memo и дай список задач.
Ассистент вызовет memo_upload_file, а затем будет опрашивать memo_get_transcription, пока
расшифровка не будет готова. Нужен ключ с правом загрузки; работает только с локальным
сервером — удаленный коннектор не имеет доступа к файлам на вашем диске.
Ответ
201 Created — файл принят и поставлен в очередь. Расшифровка идет асинхронно.
{
"id": 12345,
"uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "queued"
}| Поле | Тип | Описание |
|---|---|---|
id | integer | Внутренний числовой id. |
uuid | UUID | Используйте с Получением расшифровки для опроса и результата. |
status | string | При успехе всегда queued. |
Статусы и опрос
Опрашивайте GET /transcriptions/{uuid} раз в 5–10 секунд до терминального статуса:
status | Значение |
|---|---|
queued | Принято; ждет слот обработки. |
processing | Расшифровка идет. |
completed | Готово — в ответе появились text и prompt_results. Терминальный. |
failed | Не удалось обработать — см. error_code ниже. Терминальный. |
insufficient_balance | Не хватило минут тарифа. Файл не сохраняется — пополните баланс и загрузите заново. Терминальный. |
import time
while True:
t = httpx.get(f"{BASE}/transcriptions/{uuid}", headers=HEADERS).json()
if t["status"] in ("completed", "failed", "insufficient_balance"):
break
time.sleep(10)Частые значения error_code при failed:
| Код | Значение |
|---|---|
FILE_CORRUPTED | Файл не читается как медиа (не те байты, битый контейнер). |
FILE_NO_AUDIO | Нет аудиодорожки (например, видео без звука). |
RECORDING_TOO_LONG | Длиннее 10 часов. |
UPLOAD_INCOMPLETE | Байтов пришло меньше, чем обещал Content-Length — загрузите заново. |
Лимиты и списание
| Лимит | Значение |
|---|---|
| Размер файла | 1 КБ – 2 ГБ, на любом тарифе с доступом к API. |
| Длительность | 1 секунда – 10 часов. |
| Форматы | Аудио: mp3, wav, m4a, aac, ogg, flac, opus, amr, wma, aiff и другие. Видео: mp4, mov, mkv, avi, webm, mpeg и другие — звук извлекается автоматически. |
| Параллельность | Файлы обрабатываются параллельно по вашему тарифу — лишние не отклоняются, ждут в статусе queued и стартуют сами. Одновременных заливок отдельный лимит (10 на ключ, 16 на workspace); сверх него 429 — повторяйте с джиттером. |
| Списание | Обычные минуты тарифа, как при загрузке в приложении. Минуты резервируются при старте обработки. |
Анти-абьюз ограничители (суточные капы на ключ, лимит одновременных загрузок) выставлены сильно
выше нормального использования — если получили 429 с upload_quota_exceeded, напишите в
поддержку, поднимем.
Ретраи
Без предосторожностей повтор загрузки, ответ на которую вы не увидели (соединение оборвалось
после последнего байта), создал бы вторую расшифровку и второе списание. Заголовок
Idempotency-Key решает это:
- Передавайте уникальное значение на файл (UUID идеален) с каждой попыткой.
- Если файл уже принят под этим ключом, придет
200с оригинальнымuuidвместо дубля — без двойного списания, квоты не тронуты. - Запрос с тем же ключом, который еще в полете, вернет
409 idempotency_conflict— подождитеRetry-Afterи повторите. - Добавляйте джиттер: спите случайную долю
Retry-After, а не ровно указанное время. Если лимит поймали сразу много клиентов, одновременное пробуждение просто воссоздаст очередь. - Запоминается только успех (на 24 часа); после неудачной попытки ключ свободен для повтора.
curl -X POST "https://app.memoai.tech/api/v1/developer/transcriptions" \
-H "Authorization: Bearer mk_live_your_key_here" \
-H 'Content-Disposition: attachment; filename="standup.mp3"' \
-H "Idempotency-Key: 7f3a2b1c-9d4e-4f5a-8b6c-1d2e3f4a5b6c" \
--data-binary @standup.mp3Без Idempotency-Key повторяйте только при ошибках
Если заголовок не передаете — никогда не шлите файл повторно после 201; повторяйте только
при сетевых сбоях, 429 (после паузы из Retry-After) и 5xx.
Ошибки
| Статус | Код | Когда |
|---|---|---|
400 | unsupported_file_format / file_too_small / filename_required | Неподдерживаемое расширение, < 1 КБ или нет Content-Disposition. |
402 | insufficient_balance | Минуты тарифа закончились. |
403 | upload_scope_required | У ключа нет права загрузки. |
408 | upload_timeout | Загрузка зависла (нет данных 60 с) или шла дольше 90 минут. |
411 | length_required | Нет Content-Length. |
413 | file_size_limit_exceeded | Больше 2 ГБ. |
429 | too_many_concurrent_uploads / too_many_queued_files / upload_quota_exceeded | Лимит параллельности, очереди или суточный кап — уважайте Retry-After. |
Полный справочник и правила ретраев — в разделе Ошибки.