ДокументацияРасшифровка в реальном времени

Расшифровка в реальном времени

Отправляйте звук с микрофона или вкладки в transcript1 по WebSocket и получайте строки субтитров, при желании с переводом, прямо во время речи.

Расшифровка в реальном времени превращает аудиопоток в строки субтитров, пока люди ещё говорят. Клиент отправляет по WebSocket сырой PCM-звук, а transcript1 возвращает строки: сначала это черновой вариант, затем окончательный текст. Добавьте translate_to, и у каждой строки появится перевод. После завершения сессии результат сохраняется как обычная транскрибация.

Отдельных тарифов для live нет: расшифровка в реальном времени списывает минуты с того же баланса, что и всё остальное. Как считается время подключения, читайте в разделе «Оплата».

Когда нужен live

Выбирайте live, еслиВыбирайте обычную транскрибацию, если
Звук ещё создаётся: звонок, доклад, трансляция, видео, которое вы смотрите.У вас есть ссылка или готовый файл.
Субтитры нужны через секунду-две после слов.Важна максимальная точность, а результат можно подождать.
Рядом с каждой строкой нужен перевод в реальном времени.Нужен перевод готового транскрипта, в том числе на несколько языков.

Live принимает только звук в виде сырого PCM. Ссылки на видео, загруженные файлы, WebM, Opus и MP3 не поддерживаются: запишите звук на стороне клиента и сначала преобразуйте его в PCM. Как это сделать, показано в разделе «Захват звука в браузере».

Быстрый старт с SDK

Установите SDK версии 1.5.0 или новее: npm i @transcript1/sdk@latest. Метод t1.live.start создаёт сессию, подключается и возвращает результат, когда сессия уже началась, поэтому звук можно отправлять сразу.

import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
import { Transcript1 } from '@transcript1/sdk';
 
const t1 = new Transcript1(); // reads TRANSCRIPT1_API_KEY
 
const live = await t1.live.start({ language: 'en', translateTo: 'es', sampleRate: 16000 });
 
live.on('line', line => {
  const mark = line.final ? 'final  ' : 'partial';
  console.log(mark, line.text, '→', line.translation?.text ?? '');
});
live.on('warning', warning => console.warn(warning.code));
 
// speech.pcm: 16 kHz, mono, signed 16-bit little-endian, no header
for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
  live.send(chunk);
  await sleep(100); // 3,200 bytes are 100 ms of audio: send at real-time speed
}
 
const result = await live.end();
console.log(result.reason, result.transcriptionId, result.minutesCharged);

Строки обновляются на месте. Когда приходит строка с уже известным id, замените ею прежнюю или просто читайте все строки из live.lines. Метод end() завершает сессию, дожидается последних строк и сохраняет транскрипт. Все методы и события описаны в разделе «SDK для Node.js».

Быстрый старт с чистым WebSocket

Без SDK нужны два шага: создать сессию по HTTPS, затем открыть WebSocket с одноразовым токеном из ответа.

Создание сессии

curl -X POST https://api.transcript1.com/v1/live/sessions \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"language": "en", "translate_to": "es", "sample_rate": 16000}'

API отвечает кодом 201:

{
  "id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
  "status": "waiting",
  "transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
  "websocket_url": "wss://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD/stream",
  "token": "Zk3x...",
  "token_expires_at": "2026-11-02T12:01:00Z",
  "rate": 1
}

Если save равен false, transcription_id будет null. Токен одноразовый и действует 60 секунд, поэтому подключайтесь сразу. rate — сколько минут баланса списывается за одну начатую минуту этой сессии; подробнее в разделе «Оплата».

В теле запроса можно передать такие поля. Все они необязательны, нужное разрешение — transcriptions:write:

ПолеПо умолчаниюПравило
languageautoauto или двухбуквенный код языка, который поддерживает live.
translate_toнетДвухбуквенный код языка. На сессию приходится один язык перевода. См. «Перевод в реальном времени».
diarizefalseПодписывать говорящих. В некоторых конфигурациях разметка недоступна, например вместе с language: "auto", и API отвечает 422. Проверьте возможности.
audio_formatpcm_s16leЕдинственное значение. Поле нужно, чтобы позже можно было добавить другие форматы.
sample_rate16000Целое число от 8000 до 48000. Только моно.
savetrueПри false после завершения сессии ничего не хранится. См. «Сохранённые транскрипты».

Подключение и передача звука

Откройте WebSocket, передав токен вторым субпротоколом. Так можно подключаться из браузера и из Node 22+ без собственных заголовков. Дождитесь session.started, прежде чем отправлять звук: бинарные кадры, отправленные раньше, отбрасываются, а вы получите предупреждение audio_dropped.

import { createReadStream } from 'node:fs';
import { setTimeout as sleep } from 'node:timers/promises';
 
const session = await fetch('https://api.transcript1.com/v1/live/sessions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TRANSCRIPT1_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ language: 'en', translate_to: 'es', sample_rate: 16000 }),
}).then(response => response.json());
 
const ws = new WebSocket(session.websocket_url, ['t1-live', session.token]);
const lines = new Map();
 
ws.addEventListener('message', async message => {
  const event = JSON.parse(message.data);
 
  if (event.type === 'session.started') {
    for await (const chunk of createReadStream('./speech.pcm', { highWaterMark: 3200 })) {
      ws.send(chunk);
      await sleep(100);
    }
    ws.send(JSON.stringify({ type: 'end' }));
  } else if (event.type === 'line') {
    lines.set(event.line.id, event.line); // the full current state: replace by id
    console.log(event.line.final, event.line.text, event.line.translation?.text);
  } else if (event.type === 'session.ended') {
    console.log('ended:', event.reason, event.minutes_charged);
  }
});
 
ws.addEventListener('close', event => console.log('closed', event.code));

В Node 20 встроенного WebSocket нет: используйте пакет ws с той же формой вызова new WebSocket(url, protocols).

На корректный токен сервер отвечает только субпротоколом t1-live. Неверный токен не обрывает рукопожатие: сокет открывается, вы получаете событие error, и сокет закрывается с кодом 4xxx. Благодаря этому браузер показывает настоящую причину, а не общий код 1006. См. «Коды закрытия».

Захват звука в браузере

Звук для live должен быть знаковым 16-битным моно PCM с порядком байтов little-endian и частотой sample_rate сессии. Браузер отдаёт сэмплы с плавающей точкой, поэтому преобразуйте их в AudioWorklet. Пример ниже захватывает микрофон как PCM 16 кГц блоками по 100 мс и отправляет его через браузерную точку входа SDK. getAccessToken возвращает OAuth-токен доступа; никогда не кладите API-ключ в браузер. См. «Безопасность».

import { createLiveClient } from '@transcript1/sdk/live';
 
const workletSource = `
class Pcm16Processor extends AudioWorkletProcessor {
  constructor() {
    super();
    this.buffer = new Int16Array(1600); // 100 ms at 16 kHz
    this.filled = 0;
  }
 
  process(inputs) {
    const channel = inputs[0][0];
    if (!channel) return true;
    for (let i = 0; i < channel.length; i++) {
      const sample = Math.max(-1, Math.min(1, channel[i]));
      this.buffer[this.filled++] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
      if (this.filled === this.buffer.length) {
        this.port.postMessage(this.buffer.slice());
        this.filled = 0;
      }
    }
    return true;
  }
}
registerProcessor('pcm16', Pcm16Processor);
`;
 
const client = createLiveClient({ getAccessToken: () => myApp.getOAuthAccessToken() });
 
const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1 } });
const context = new AudioContext({ sampleRate: 16000 });
const moduleUrl = URL.createObjectURL(new Blob([workletSource], { type: 'text/javascript' }));
await context.audioWorklet.addModule(moduleUrl);
 
// the context's real rate: a browser that cannot do 16 kHz picks its own
const live = await client.start({ language: 'auto', sampleRate: context.sampleRate });
live.on('line', renderLine);
 
const microphone = context.createMediaStreamSource(stream);
const capture = new AudioWorkletNode(context, 'pcm16');
capture.port.onmessage = event => live.send(event.data); // an Int16Array
const mute = context.createGain();
mute.gain.value = 0;
microphone.connect(capture).connect(mute).connect(context.destination);
 
async function stop() {
  stream.getTracks().forEach(track => track.stop());
  await context.close();
  return live.end();
}

Скрипт AudioWorklet рассчитан на 16 кГц. Если контекст работает на другой частоте, блок перестаёт быть равным 100 мс, но PCM остаётся корректным, потому что sampleRate совпадает с контекстом. Чтобы захватить звук вкладки или видео вместо микрофона, создайте MediaStream через getDisplayMedia или из captureStream() медиаэлемента и подключите его так же.

Перевод в реальном времени

Добавьте в сессию translate_to, и transcript1 будет переводить каждую строку по мере произнесения.

  • На сессию приходится один язык перевода. Другие языки можно добавить к сохранённому транскрипту позже через эндпоинт перевода.
  • В каждой строке line есть оригинал (text, final) и объект translation (language, text, final). Если translate_to не задан, translation равен null.
  • Оригинал и перевод становятся окончательными независимо друг от друга: у строки оригинал уже может быть финальным, а перевод ещё меняться. Показывайте строку как финальную, когда окончательны оба.
  • Если строка уже на целевом языке, её собственный текст служит переводом и становится финальным, когда строка закрывается.
  • Строка закрывается, когда говорящий делает паузу, меняется говорящий, пауза между словами превышает 0.9 секунды, строка достигает двух строк субтитров (84 символа) или 15 секунд, либо вы отправляете finalize. При включённом переводе закрытие может занять примерно на 3 секунды больше, пока приходит перевод. Тогда перевод может оставаться незавершённым (final: false) и продолжать расти, даже когда оригинал уже финальный.
  • Перевод бесплатный и минуты не расходует.

Какие языки перевода и какие пары доступны, зависит от поставщика распознавания речи в реальном времени. Читайте возможности, а не зашивайте правила в код. Неподдерживаемый язык перевода вернёт 422 unsupported_translation. Например, поставщик может требовать явный language вместо auto или разрешать только пары с английским.

Протокол WebSocket

Подключение

new WebSocket(websocket_url, ['t1-live', token]);

Токен передаётся как субпротокол WebSocket. Он не попадает ни в URL, ни в журналы доступа. Заголовок Authorization не отправляйте: учётными данными служит сам токен. Сервер шлёт ping каждые 30 секунд; браузеры и пакет ws отвечают автоматически. Сокет, который не ответил pong за 60 секунд, отключается.

Корректное подключение к сессии, у которой уже есть сокет, заменяет старый. См. «Возобновление и перехват».

Сообщения клиента

СообщениеЗначение
Бинарный кадрЗвук: PCM s16le, моно, с sample_rate сессии. Длина кадра чётная, размер не больше 256 KB. Хороший размер — около 100 мс звука на кадр.
{"type":"finalize"}Закрыть текущую строку сейчас, например при паузе видео.
{"type":"end"}Завершить сессию и сохранить её. Сервер отвечает session.ended и закрывает сокет.
Любое другоеНефатальное событие error с кодом invalid_message.

Кадр нечётной длины или слишком большого размера считается нарушением протокола и закрывает сокет с кодом 4008.

Начинайте отправлять звук после session.started. Если клиент отправляет звук быстрее реального времени, оплачивается длительность звука, а не время подключения (см. «Оплата»), поэтому отправляйте звук с той скоростью, с какой он создаётся.

События сервера

Каждое событие — это текстовый JSON-кадр с полем type.

СобытиеКогда приходит
session.startedПодключение принято. С этого момента отправляйте звук.
lineСтрока субтитров создана или изменилась.
usageПосле каждого списания.
warningНужно обратить внимание, но сессия продолжается.
errorНефатальная проблема или причина немедленного закрытия.
reconnectСервер скоро перезапустится. Возобновите сессию.
session.endedСессия завершена и сохранена. Последнее событие перед обычным закрытием.

В session.started указано, возобновлена ли сессия и сколько звука она уже обработала:

{
  "type": "session.started",
  "session_id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
  "transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
  "resumed": false,
  "offset_ms": 0
}

line содержит полное текущее состояние одной строки, поэтому заменяйте имеющуюся строку с тем же id. См. «Объект строки».

{
  "type": "line",
  "line": {
    "id": 12,
    "start_ms": 53120,
    "end_ms": 56040,
    "speaker": null,
    "language": "en",
    "text": "Welcome back to the stream",
    "final": true,
    "translation": { "language": "es", "text": "Bienvenidos de nuevo", "final": false }
  }
}

usage приходит после каждого списания: время подключения, длительность звука, списанные к этому моменту минуты баланса и сколько минут осталось:

{
  "type": "usage",
  "connected_ms": 61240,
  "audio_ms": 60100,
  "minutes_charged": 2,
  "minutes_remaining": 898
}

У warning есть code:

codeЗначение
balance_lowСледующее списание не пройдёт. Когда оно наступит, сессия завершится с balance_exhausted. Не отправляется, пока включено автопополнение.
audio_droppedЗвук пришёл до готовности сессии или его пришло слишком много, пока подключался поставщик распознавания. Самый старый звук отброшен.
idle_timeout_soonЗвука нет уже 4 минуты. Сессия закончится через 5 минут без звука. Отправьте звук, чтобы сохранить её.
{ "type": "warning", "code": "idle_timeout_soon" }

У error есть code и message. По живому сокету могут прийти такие коды:

codeФатальнаяЗначение
invalid_messageНетТекстовый кадр, который не является finalize или end.
invalid_tokenДаТокен неверен, истёк или уже использован. Сокет закрывается с 4001.
not_foundДаСессии не существует. Сокет закрывается с 4004.
session_endedДаСессия уже завершена. Сокет закрывается с 4004.
{ "type": "error", "code": "invalid_message", "message": "Expected {\"type\":\"finalize\"} or {\"type\":\"end\"}" }

reconnect приходит до того, как сервер закроет сокет с кодом 1012, например во время деплоя. Получите новый токен и возобновите сессию.

{ "type": "reconnect", "reason": "server_restart" }

session.ended — последнее событие каждой сессии. Числа в нём — итоговые:

{
  "type": "session.ended",
  "reason": "client_ended",
  "transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
  "minutes_charged": 3,
  "connected_ms": 142500,
  "audio_ms": 141900
}

Объект строки

ПолеЗначение
idЧисло с нуля, которое растёт на единицу с каждой строкой. Это индекс сегмента в сохранённом транскрипте.
start_ms, end_msНачало и конец во времени звука сессии. Это время продолжается после переподключений.
speakerМетка говорящего, если включён diarize, иначе null. Метки такие же, как в обычных транскриптах.
languageОпределённый или заданный язык строки либо null, если он ещё неизвестен.
textТекст оригинала на данный момент.
finaltrue, когда текст оригинала больше не изменится.
translationnull без translate_to, иначе language, text и final.

Строки с final: false показывайте более бледным стилем: их текст ещё может измениться. Текст строки с final: true больше не меняется, и финальная строка никогда не удаляется.

В SDK поля строки пишутся в camelCase: startMs, endMs.

Причины завершения

session.ended и GET /v1/live/sessions/:id возвращают end_reason:

ПричинаЗначение
client_endedВы отправили end.
balance_exhaustedСледующее списание не прошло. Сессия завершается на границе минуты и сохраняется.
idle_timeoutЗвука не было 5 минут.
max_durationСессия была подключена 300 минут. Начните новую.
disconnectedКлиент отсутствовал больше 2 минут и не возобновил сессию.
upstream_errorСбой у поставщика распознавания речи.
internal_errorОшибка на нашей стороне.
not_connectedК сессии не подключились за 5 минут. За неё ничего не списывается, а увидеть её можно только через GET.

Коды закрытия

КодЗначение
1000Обычное закрытие. Всегда следует за session.ended.
1011Неожиданная ошибка сервера. Сервер восстанавливает сессию: возобновите её с новым токеном.
1012Перезапуск сервера. Идёт после reconnect: возобновите сессию с новым токеном.
4001Токен неверен, истёк или уже использован.
4004Сессия не найдена или уже завершена.
4008Нарушение протокола: бинарный кадр нечётной длины или слишком большого размера.
4010Заменено более новым подключением к той же сессии.

Пока API перезапускается, на новый запрос WebSocket может прийти HTTP 503. Повторите попытку чуть позже.

Возобновление и перехват

Сессия переживает обрыв сети, деплой API и сбой. После обрыва она 2 минуты ждёт вас, а затем завершается с причиной disconnected и сохраняется.

  1. Вызовите POST /v1/live/sessions/:id/token. В ответе будут token, token_expires_at и websocket_url, те же поля, что и при создании сессии. Когда сессия уже завершена, вызов вернёт 409 session_ended.
  2. Откройте новый WebSocket с этим токеном.
  3. Придёт session.started с resumed: true. offset_ms показывает, сколько звука сессия уже обработала: продолжайте с этого места. Идентификаторы строк продолжают нумерацию.

Строки, которые уже были финальными, сохраняются. Незавершённый хвост на момент обрыва теряется, поэтому, если вы буферизуете звук, отправьте заново несколько секунд с offset_ms. Время переподключения не оплачивается.

Перехват — это тот же вызов. Если сервер ещё считает сокет открытым, новое корректное подключение заменяет его, а старый сокет закрывается с 4010 после сохранения его строк. Лимит одновременных сессий возобновлению не мешает.

SDK делает всё это за вас: при обрыве или событии reconnect он получает токен и переподключается с задержкой от 0.5 до 8 секунд в течение 2 минут, а затем повторно отправляет последние 10 секунд звука, отправленного за время обрыва.

Оплата

Live списывает минуты с того же баланса, что и обычные транскрибации.

  • Оплачивается время подключения с момента принятия сокета до его закрытия. Тишина и видео на паузе тоже считаются. Время между обрывом и возобновлением не считается.
  • За каждую начатую минуту, минимум одна. Первая минута списывается при первом принятом подключении, каждая следующая — когда начинается.
  • Быстрее реального времени оплачивается как длительность звука. Если отправленный звук длиннее времени подключения, оплачивается длительность звука.
  • Тариф берите из API. Начатая минута стоит rate минут баланса с округлением вверх. Обычно значение равно 1, но может быть дробным. Текущее значение читайте из rates.live в GET /v1/account, из rate в GET /v1/live/capabilities и из rate созданной сессии. После создания сессии её значение не меняется.
  • Перевод бесплатный.
  • Без подключения нет списания. Сессия, к которой не подключились за 5 минут, завершается как not_connected.
  • При сбоях деньги возвращаются. Если сессия завершилась с upstream_error или internal_error, не выдав ни одной строки, все списания возвращаются. Пустая сессия из-за тишины оплачивается и сохраняется пустой.
  • Когда баланс заканчивается и включено автопополнение, transcript1 списывает оплату с сохранённой карты, пока сессия продолжает стримить, и сессия продолжается. Если автопополнение выключено или приостановлено либо списание не прошло, сессия завершается, сохраняется и закрывается с balance_exhausted на границе минуты. Сначала приходит предупреждение balance_low, если только не включено автопополнение.

Если доступного баланса меньше одной начатой минуты по текущему тарифу, создание сессии вернёт 402 insufficient_minutes. Если включено автопополнение, transcript1 сначала пробует пополнить баланс. См. «Тарифы и лимиты».

Лимиты

FreeMonthlyAnnual
Одновременных live-сессий123
  • Сессия учитывается, пока она в статусе waiting, connected или disconnected (в пределах двухминутного окна). При превышении лимита POST /v1/live/sessions возвращает 429 too_many_live_sessions с Retry-After: 30.
  • Live-сессии не входят в лимит активных задач.
  • Сессия длится не больше 300 минут времени подключения, после чего завершается с max_duration.
  • Сессия без звука 5 минут завершается с idle_timeout; предупреждение idle_timeout_soon приходит через 4 минуты. Поток на паузе по-прежнему оплачивается как время подключения и считается простоем, поэтому при долгой паузе завершайте сессию.
  • transcript1 ограничивает все live-сессии в сумме. Когда ёмкость исчерпана, POST /v1/live/sessions возвращает 503 live_capacity — такую ошибку можно повторить. Подождите Retry-After (30 секунд) и повторите запрос. Проверка выполняется только при создании сессии, но не посреди неё.
  • Создание сессий и получение токенов входят в ваш лимит запросов в минуту.
  • Звук принимается только в виде сырого PCM: pcm_s16le, моно, от 8000 до 48000 Гц.

Возможности

GET /v1/live/capabilities описывает, что live поддерживает прямо сейчас, чтобы клиентам не приходилось зашивать правила поставщика. Нужное разрешение — transcriptions:read.

{
  "available": true,
  "auto_language": true,
  "languages": ["en", "es"],
  "translation": {
    "targets": ["es", "de"],
    "pairs": "any",
    "requires_language": false
  },
  "diarize": true,
  "audio_formats": ["pcm_s16le"],
  "sample_rate": { "min": 8000, "max": 48000 },
  "max_session_minutes": 300,
  "rate": 1
}

Здесь списки сокращены. Полные читайте из API.

  • translation.pairs равен "any" (любой определённый язык в любой целевой) или списку объектов с from и to.
  • translation.requires_language равен true, если для перевода нужен явный language вместо auto.
  • Когда live не настроен, ответ содержит available: false и только rate, а создание сессии возвращает 503 live_unavailable.

В SDK: await t1.live.capabilities().

Чтение сессии

GET /v1/live/sessions/:id возвращает состояние сессии. Нужное разрешение — transcriptions:read.

curl https://api.transcript1.com/v1/live/sessions/lv_8fK2Lm0PqRsTuVwXyZaBcD \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
{
  "id": "lv_8fK2Lm0PqRsTuVwXyZaBcD",
  "status": "ended",
  "end_reason": "client_ended",
  "transcription_id": "tr_3NcQvXy7BtHjKd5ErFgLmA",
  "options": {
    "language": "en",
    "translate_to": "es",
    "diarize": false,
    "audio_format": "pcm_s16le",
    "sample_rate": 16000,
    "save": true
  },
  "connected_ms": 142500,
  "audio_ms": 141900,
  "minutes_charged": 3,
  "rate": 1,
  "created_at": "2026-11-02T11:58:12Z",
  "ended_at": "2026-11-02T12:00:35Z"
}

status принимает значения waiting, connected, disconnected или ended. end_reason равен null, пока сессия не завершена. В SDK: await t1.live.get(id).

Ошибки

Ошибки запросов приходят в обычном формате ошибки. Вот те, что возвращают POST /v1/live/sessions и соседние эндпоинты:

HTTP-статусcodeМожно повторитьКогда
422invalid_requestНетПоле пропущено или неверно, например sample_rate вне диапазона от 8000 до 48000.
422unsupported_languageНетlanguage не поддерживается в live.
422unsupported_translationНетЯзык перевода или пара языков не поддерживается.
402insufficient_minutesНетДоступный баланс меньше одной начатой минуты по текущему тарифу.
403email_not_verifiedНетСначала подтвердите почту.
429too_many_live_sessionsДаЗаняты все одновременные live-сессии вашего тарифа. Подождите Retry-After.
503live_capacityДаВся ёмкость live занята. Подождите Retry-After (30 секунд).
503live_unavailableНетРасшифровка в реальном времени сейчас недоступна.
409session_endedНетPOST /v1/live/sessions/:id/token для завершённой сессии.

Проблемы на сокете приходят как события error и коды закрытия.

Сохранённые транскрипты

При save: true (по умолчанию) после завершения сессия сохраняется как обычная транскрибация. Сам звук не хранится никогда.

  • transcription_id возвращается при создании сессии. Пока сессия идёт, у неё статус live, после завершения — completed. Если к сессии так и не подключились, остаётся транскрибация со статусом canceled.
  • У транскрибации есть source: { "platform": "live", "session_id": "lv_…" }. Ссылки и файла нет. В личном кабинете она отображается как live-сессия.
  • Каждая строка становится одним сегментом с тем же индексом, что и id строки. Транскрипт можно читать как JSON, текст, SRT или VTT, как любую другую транскрибацию: см. справочник API.
  • Перевод, сделанный в реальном времени, сохраняется вместе с ней. Читайте его с параметром translation, как описано в разделе «Перевод».
  • Когда транскрибация получит статус completed, другие языки перевода можно добавить позже через POST /v1/transcriptions/:id/translations. См. «Перевод».

При save: false после завершения сессии ничего не хранится: транскрибации нет, а transcription_id равен null. Все строки вы по-прежнему получаете по сокету, и списание остаётся обычным.

Безопасность

  • Токен, который вы получаете при создании сессии, одноразовый и действует 60 секунд. Он передаётся как субпротокол WebSocket, а не в URL, поэтому не попадает в журналы доступа. Утёкший токен бесполезен после использования или истечения срока.
  • Используйте API-ключ только на сервере, который вы контролируете. Никогда не вставляйте API-ключ в веб-страницу или расширение.
  • В браузере или расширении входите через OAuth и передавайте OAuth-токен доступа в getAccessToken метода createLiveClient. Для запуска сессий токену нужно разрешение transcriptions:write. OAuth-токены доступа истекают через 1 час, и при каждом возобновлении getAccessToken запрашивается заново.
  • Сессию может создать и ваш сервер с API-ключом, передав браузеру только websocket_url и token. Тогда клиент подключается напрямую. Без нового токена от вас он не сможет возобновить сессию.

Дата обновления 3 ноября 2026 г.