DokumentasiTranskripsi langsung

Transkripsi langsung

Kirim audio mikrofon atau tab ke transcript1 lewat WebSocket dan terima baris subtitle, dengan terjemahan real-time opsional, saat orang masih berbicara.

Transkripsi langsung mengubah aliran audio menjadi baris subtitle saat orang masih berbicara. Klien Anda mengirim audio PCM mentah lewat WebSocket, lalu transcript1 mengirim balik baris yang awalnya berupa dugaan sementara dan kemudian menjadi final. Tambahkan translate_to agar setiap baris juga membawa terjemahannya. Setelah sesi berakhir, hasilnya disimpan sebagai transkripsi biasa.

Tidak ada paket khusus untuk fitur langsung: transkripsi langsung memakai saldo menit yang sama dengan fitur lainnya. Lihat Biaya untuk cara waktu terhubung dihitung.

Kapan memakai transkripsi langsung

Pakai transkripsi langsung jikaPakai transkripsi biasa jika
Audio masih berlangsung: panggilan, presentasi, siaran, atau video yang sedang Anda tonton.Anda punya tautan atau file yang sudah jadi.
Anda butuh subtitle satu atau dua detik setelah ucapan.Anda mengutamakan akurasi terbaik dan bisa menunggu hasilnya.
Anda ingin terjemahan real-time di samping setiap baris.Anda ingin menerjemahkan transkrip yang sudah selesai, atau ke beberapa bahasa.

Transkripsi langsung hanya menerima audio, dalam bentuk PCM mentah. Tautan video, unggahan file, WebM, Opus, dan MP3 tidak diterima. Tangkap audio di klien dan ubah ke PCM terlebih dahulu. Menangkap audio di browser menunjukkan caranya.

Mulai cepat dengan SDK

Pasang SDK 1.5.0 atau yang lebih baru: npm i @transcript1/sdk@latest. t1.live.start membuat sesi, terhubung, lalu selesai setelah sesi dimulai, sehingga Anda bisa langsung mengirim audio.

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);

Baris diperbarui di tempat. Ganti baris yang sudah Anda punya ketika baris dengan id yang sama tiba, atau baca semuanya dari live.lines. end() menyelesaikan sesi, menunggu baris terakhir, dan menyimpan transkrip. Lihat SDK Node.js untuk semua metode dan event.

Mulai cepat dengan WebSocket mentah

Tanpa SDK ada dua langkah: buat sesi lewat HTTPS, lalu buka WebSocket dengan token sekali pakai yang dikembalikan.

Membuat sesi

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 menjawab 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
}

transcription_id bernilai null jika save adalah false. Token hanya berlaku sekali dan kedaluwarsa dalam 60 detik, jadi segera terhubung. rate adalah jumlah menit saldo yang ditagih per menit yang dimulai dalam sesi ini; lihat Biaya.

Body request menerima field berikut. Semuanya opsional, dan scope yang dibutuhkan adalah transcriptions:write:

FieldBawaanAturan
languageautoauto, atau kode dua huruf yang didukung transkripsi langsung.
translate_totidak adaKode dua huruf. Satu bahasa tujuan per sesi. Lihat Terjemahan langsung.
diarizefalseMemberi label pembicara. Sebagian konfigurasi tidak bisa memberi label pembicara, misalnya bersama language: "auto", dan menjawab 422. Periksa kemampuan.
audio_formatpcm_s16leSatu-satunya nilai. Field ini ada agar format lain bisa ditambahkan nanti.
sample_rate16000Bilangan bulat dari 8000 sampai 48000. Hanya mono.
savetruefalse tidak menyimpan apa pun setelah sesi berakhir. Lihat Transkrip tersimpan.

Terhubung dan streaming

Buka WebSocket dengan token sebagai subprotokol kedua. Cara ini berjalan di browser dan di Node 22+ tanpa header khusus. Tunggu session.started sebelum mengirim audio: frame biner yang dikirim lebih awal dibuang, dan Anda mendapat peringatan 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 tidak punya WebSocket bawaan: pakai paket ws, yang memiliki bentuk new WebSocket(url, protocols) yang sama.

Server menjawab token yang valid hanya dengan subprotokol t1-live. Token yang salah tidak pernah menggagalkan handshake: socket terbuka, Anda menerima event error, lalu socket ditutup dengan kode 4xxx, sehingga browser menampilkan alasan sebenarnya, bukan 1006 yang generik. Lihat Kode penutupan.

Menangkap audio di browser

Audio untuk transkripsi langsung harus berupa PCM mono 16-bit bertanda little-endian dengan sample_rate sesi. Browser memberi sampel floating-point, jadi ubah di dalam AudioWorklet. Contoh ini menangkap mikrofon sebagai PCM 16 kHz dalam potongan 100 ms dan mengirimkannya lewat entri SDK untuk browser. getAccessToken mengembalikan access token OAuth; jangan pernah menaruh kunci API di browser. Lihat Keamanan.

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();
}

Worklet ini ditulis untuk 16 kHz. Jika konteks berjalan pada laju lain, potongan tidak lagi 100 ms, tetapi PCM tetap benar karena sampleRate sama dengan konteks. Untuk menangkap suara tab atau video, bukan mikrofon, buat MediaStream dengan getDisplayMedia atau dari captureStream() elemen media, lalu sambungkan dengan cara yang sama.

Terjemahan langsung

Tambahkan translate_to ke sesi, dan transcript1 menerjemahkan setiap baris saat diucapkan.

  • Satu bahasa tujuan per sesi. Tambahkan bahasa lain ke transkrip tersimpan setelahnya dengan endpoint terjemahan.
  • Setiap line punya teks asli (text, final) dan objek translation (language, text, final). translation bernilai null jika translate_to tidak diatur.
  • Teks asli dan terjemahan menjadi final secara terpisah: satu baris bisa punya teks asli yang final sementara terjemahannya masih berubah. Tampilkan baris sebagai final setelah keduanya final.
  • Baris yang sudah berbahasa tujuan memakai teksnya sendiri sebagai terjemahan, dan menjadi final saat baris ditutup.
  • Baris ditutup saat pembicara berhenti sejenak, pembicara berganti, jeda antarkata lebih dari 0.9 detik, baris mencapai dua baris subtitle (84 karakter) atau 15 detik, atau Anda mengirim finalize. Saat terjemahan aktif, penutupan baris bisa memakan sekitar 3 detik lebih lama sampai terjemahannya tiba. Dalam hal itu terjemahan bisa tetap terbuka (final: false) dan terus bertambah setelah teks asli final.
  • Terjemahan gratis. Tidak memakai menit.

Bahasa tujuan dan pasangan bahasa yang tersedia bergantung pada penyedia ucapan langsung. Baca kemampuan alih-alih menuliskan aturan secara permanen di kode. Tujuan yang tidak didukung menghasilkan 422 unsupported_translation. Misalnya, penyedia bisa mewajibkan language yang eksplisit alih-alih auto, atau hanya mengizinkan pasangan yang menyertakan bahasa Inggris.

Protokol WebSocket

Terhubung

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

Token dikirim sebagai subprotokol WebSocket. Token tidak pernah muncul di URL atau log akses. Jangan kirim header Authorization: token itulah kredensialnya. Server mengirim ping setiap 30 detik; browser dan paket ws menjawab otomatis. Socket yang tidak mengirim pong selama 60 detik diputus.

Koneksi valid ke sesi yang sudah punya socket akan menggantikan socket lama. Lihat Melanjutkan dan mengambil alih.

Pesan dari klien

PesanArti
Frame binerAudio: PCM s16le mono dengan sample_rate sesi. Setiap frame berukuran genap dan paling besar 256 KB. Sekitar 100 ms per frame adalah ukuran yang baik.
{"type":"finalize"}Menutup baris saat ini sekarang juga, misalnya saat video dijeda.
{"type":"end"}Mengakhiri sesi dan menyimpannya. Server menjawab session.ended lalu menutup socket.
Selain ituEvent error yang tidak fatal dengan kode invalid_message.

Frame berukuran ganjil atau terlalu besar adalah pelanggaran protokol dan menutup socket dengan 4008.

Mulai kirim audio setelah session.started. Klien yang mengirim audio lebih cepat dari waktu nyata ditagih berdasarkan durasi audio, bukan waktu terhubung (lihat Biaya), jadi kirim audio sesuai kecepatan audio itu dihasilkan.

Event dari server

Setiap event adalah frame teks JSON dengan type.

EventDikirim saat
session.startedKoneksi diterima. Kirim audio mulai sekarang.
lineBaris subtitle dibuat atau berubah.
usageSetelah setiap penagihan.
warningAda hal yang perlu diperhatikan, tetapi sesi berlanjut.
errorMasalah yang tidak fatal, atau alasan penutupan seketika.
reconnectServer akan segera restart. Lanjutkan sesi.
session.endedSesi selesai dan tersimpan. Event terakhir sebelum penutupan normal.

session.started menyatakan apakah ini kelanjutan sesi dan berapa banyak audio yang sudah diproses sesi:

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

line membawa keadaan lengkap terkini dari satu baris, jadi ganti baris yang Anda punya dengan id yang sama. Lihat Objek baris.

{
  "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 dikirim setelah setiap penagihan, berisi waktu terhubung, durasi audio, menit saldo yang sudah ditagih, dan menit yang tersisa:

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

warning memiliki code:

codeArti
balance_lowPenagihan berikutnya akan gagal. Sesi berakhir dengan balance_exhausted saat waktunya tiba. Tidak dikirim saat top-up otomatis aktif.
audio_droppedAudio tiba sebelum sesi siap, atau terlalu banyak audio tiba saat penyedia ucapan sedang terhubung. Audio terlama dibuang.
idle_timeout_soonTidak ada audio selama 4 menit. Sesi berakhir setelah 5 menit tanpa audio. Kirim audio agar sesi tetap berjalan.
{ "type": "warning", "code": "idle_timeout_soon" }

error memiliki code dan message. Kode berikut bisa tiba di socket langsung:

codeFatalArti
invalid_messageTidakFrame teks yang bukan finalize atau end.
invalid_tokenYaToken tidak valid, kedaluwarsa, atau sudah dipakai. Socket ditutup dengan 4001.
not_foundYaSesi tidak ada. Socket ditutup dengan 4004.
session_endedYaSesi sudah berakhir. Socket ditutup dengan 4004.
{ "type": "error", "code": "invalid_message", "message": "Expected {\"type\":\"finalize\"} or {\"type\":\"end\"}" }

reconnect datang sebelum server menutup socket dengan 1012, misalnya saat deploy. Ambil token baru dan lanjutkan sesi.

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

session.ended adalah event terakhir setiap sesi. Angkanya adalah total akhir:

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

Objek baris

FieldArti
idNomor berbasis 0 yang bertambah satu untuk setiap baris. Ini adalah indeks segmen di transkrip tersimpan.
start_ms, end_msAwal dan akhir dalam waktu audio sesi. Waktu ini berlanjut melewati sambungan ulang.
speakerLabel pembicara jika diarize aktif, selain itu null. Labelnya sama dengan transkrip biasa.
languageBahasa baris yang terdeteksi atau ditentukan, atau null jika belum diketahui.
textTeks asli sejauh ini.
finaltrue setelah teks asli tidak akan berubah lagi.
translationnull tanpa translate_to, selain itu language, text, dan final.

Tampilkan baris dengan final: false dengan gaya yang lebih pudar: teksnya masih bisa berubah. Teks baris dengan final: true tidak pernah berubah lagi, dan baris final tidak pernah dihapus.

SDK memakai camelCase untuk field baris: startMs, endMs.

Alasan berakhir

session.ended dan GET /v1/live/sessions/:id memberikan end_reason:

AlasanArti
client_endedAnda mengirim end.
balance_exhaustedPenagihan berikutnya gagal. Sesi berakhir pada batas menit dan disimpan.
idle_timeoutTidak ada audio selama 5 menit.
max_durationSesi terhubung selama 300 menit. Mulai sesi baru.
disconnectedKlien menghilang lebih dari 2 menit tanpa melanjutkan sesi.
upstream_errorPenyedia ucapan gagal.
internal_errorTerjadi masalah di sisi kami.
not_connectedSesi tidak pernah terhubung dalam 5 menit. Sesi ini tidak pernah ditagih dan hanya terlihat lewat GET.

Kode penutupan

KodeArti
1000Penutupan normal. Selalu mengikuti session.ended.
1011Error server yang tidak terduga. Sesi dipulihkan oleh server: lanjutkan dengan token baru.
1012Server restart. Mengikuti reconnect: lanjutkan dengan token baru.
4001Token tidak valid, kedaluwarsa, atau sudah dipakai.
4004Sesi tidak ditemukan atau sudah berakhir.
4008Pelanggaran protokol: frame biner berukuran ganjil atau terlalu besar.
4010Digantikan oleh koneksi yang lebih baru ke sesi yang sama.

Selama API restart, request WebSocket baru bisa dijawab dengan HTTP 503. Coba lagi sebentar lagi.

Melanjutkan dan mengambil alih

Sesi bertahan saat jaringan terputus, saat API di-deploy, dan saat terjadi crash. Selama 2 menit setelah terputus, sesi menunggu Anda; setelah itu sesi berakhir sebagai disconnected dan disimpan.

  1. Panggil POST /v1/live/sessions/:id/token. Responsnya berisi token, token_expires_at, dan websocket_url, field yang sama seperti saat Anda membuat sesi. Panggilan ini gagal dengan 409 session_ended setelah sesi berakhir.
  2. Buka WebSocket baru dengan token itu.
  3. session.started tiba dengan resumed: true. offset_ms adalah jumlah audio yang sudah diproses sesi: lanjutkan audio dari titik itu. Id baris berlanjut.

Baris yang sudah final tetap disimpan. Ekor yang sedang berjalan saat koneksi terputus hilang, jadi jika Anda menyimpan buffer audio, kirim ulang beberapa detik audio mulai dari offset_ms. Jeda saat menyambung ulang tidak ditagih.

Pengambilalihan menggunakan panggilan yang sama. Jika server masih menganggap sebuah socket terbuka, koneksi valid yang baru menggantikannya, dan socket lama ditutup dengan 4010 setelah barisnya disimpan. Melanjutkan sesi tidak pernah terhalang oleh batas sesi bersamaan.

SDK melakukan semua ini untuk Anda: saat koneksi terputus atau event reconnect tiba, SDK mengambil token dan menyambung ulang dengan jeda bertahap 0.5 sampai 8 detik hingga 2 menit, lalu mengirim ulang 10 detik terakhir audio yang Anda kirim selama jeda.

Biaya

Transkripsi langsung memakai saldo menit yang sama dengan transkripsi batch.

  • Waktu terhubung yang ditagih, sejak socket diterima sampai ditutup. Keheningan dan video yang dijeda ikut dihitung. Waktu antara koneksi terputus dan dilanjutkan tidak dihitung.
  • Per menit yang dimulai, minimum 1. Menit pertama ditagih saat koneksi pertama diterima, dan setiap menit berikutnya saat menit itu dimulai.
  • Lebih cepat dari waktu nyata ditagih sebagai durasi audio. Jika audio yang Anda kirim lebih panjang daripada waktu terhubung, durasi audio yang ditagih.
  • Tarif dibaca dari API. Satu menit yang dimulai bernilai rate menit saldo, dibulatkan ke atas. Tarif biasanya 1 dan bisa berupa desimal. Baca tarif langsung dari rates.live di GET /v1/account, dari rate di GET /v1/live/capabilities, dan dari rate pada sesi yang Anda buat. Tarif sebuah sesi tetap setelah sesi dibuat.
  • Terjemahan gratis.
  • Tidak pernah terhubung berarti tidak ditagih. Sesi yang tidak terhubung dalam 5 menit berakhir sebagai not_connected.
  • Kegagalan dikembalikan. Jika sesi berakhir dengan upstream_error atau internal_error sebelum menghasilkan satu baris pun, semua tagihan dikembalikan. Sesi kosong akibat keheningan tetap ditagih dan disimpan kosong.
  • Saat saldo habis dan top-up otomatis aktif, transcript1 menagih kartu tersimpan Anda selagi sesi tetap streaming, dan sesi berlanjut. Jika top-up otomatis mati atau dijeda, atau penagihan gagal, sesi diselesaikan, disimpan, dan berakhir dengan balance_exhausted pada batas menit. Peringatan balance_low datang lebih dulu, kecuali top-up otomatis aktif.

Membuat sesi menghasilkan 402 insufficient_minutes jika saldo yang bisa dipakai kurang dari satu menit yang dimulai pada tarif saat ini. Jika top-up otomatis aktif, transcript1 mencoba top-up lebih dulu. Lihat Biaya dan batas penggunaan.

Batas

FreeMonthlyAnnual
Sesi langsung bersamaan123
  • Sesi dihitung selama berstatus waiting, connected, atau disconnected (dalam jendela 2 menitnya). Jika melewati batas, POST /v1/live/sessions menghasilkan 429 too_many_live_sessions dengan Retry-After: 30.
  • Sesi langsung tidak dihitung dalam batas transkripsi aktif Anda.
  • Satu sesi berlangsung paling lama 300 menit waktu terhubung. Setelah itu sesi berakhir dengan max_duration.
  • Sesi tanpa audio selama 5 menit berakhir dengan idle_timeout; Anda mendapat idle_timeout_soon setelah 4 menit. Aliran yang dijeda tetap menagih waktu terhubung dan dihitung sebagai menganggur, jadi akhiri sesi jika jedanya lama.
  • transcript1 membatasi semua sesi langsung secara bersama-sama. Jika semuanya terpakai, POST /v1/live/sessions menghasilkan 503 live_capacity, yang bisa dicoba ulang. Tunggu Retry-After (30 detik) lalu coba lagi. Batas ini diperiksa hanya saat sesi dibuat, tidak pernah di tengah sesi.
  • Membuat sesi dan mengambil token dihitung dalam batas request per menit Anda.
  • Audio hanya berupa PCM mentah: pcm_s16le, mono, 8000 sampai 48000 Hz.

Kemampuan

GET /v1/live/capabilities menjelaskan apa yang saat ini didukung transkripsi langsung, sehingga klien tidak perlu menuliskan aturan penyedia di kode. Scope yang dibutuhkan adalah 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
}

Daftar di atas dipersingkat. Baca daftar lengkapnya dari API.

  • translation.pairs bernilai "any" (bahasa terdeteksi apa pun ke tujuan apa pun), atau daftar objek dengan from dan to.
  • translation.requires_language bernilai true jika terjemahan memerlukan language yang eksplisit alih-alih auto.
  • Jika transkripsi langsung belum dikonfigurasi, responsnya available: false dengan hanya rate, dan pembuatan sesi menghasilkan 503 live_unavailable.

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

Membaca sesi

GET /v1/live/sessions/:id mengembalikan keadaan sebuah sesi. Scope yang dibutuhkan adalah 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 bernilai waiting, connected, disconnected, atau ended. end_reason bernilai null sampai sesi berakhir. Dengan SDK: await t1.live.get(id).

Error

Error request memakai struktur error yang biasa. Berikut error yang dikembalikan POST /v1/live/sessions dan endpoint pendampingnya:

Status HTTPcodeBisa dicoba ulangKapan
422invalid_requestTidakAda field yang hilang atau tidak valid, misalnya sample_rate di luar 8000 sampai 48000.
422unsupported_languageTidaklanguage tidak didukung untuk transkripsi langsung.
422unsupported_translationTidakBahasa tujuan, atau pasangan bahasanya, tidak didukung.
402insufficient_minutesTidakSaldo yang bisa dipakai kurang dari satu menit yang dimulai pada tarif saat ini.
403email_not_verifiedTidakVerifikasi alamat email Anda terlebih dahulu.
429too_many_live_sessionsYaSemua sesi langsung bersamaan pada paket Anda sedang terpakai. Tunggu sesuai Retry-After.
503live_capacityYaSeluruh kapasitas langsung sedang terpakai. Tunggu sesuai Retry-After (30 detik).
503live_unavailableTidakTranskripsi langsung sedang tidak tersedia.
409session_endedTidakPOST /v1/live/sessions/:id/token untuk sesi yang sudah berakhir.

Masalah di socket datang sebagai event error dan kode penutupan.

Transkrip tersimpan

Dengan save: true (bawaan), sesi disimpan sebagai transkripsi biasa saat berakhir. Audio tidak pernah disimpan.

  • transcription_id dikembalikan saat Anda membuat sesi. Statusnya live selama sesi berjalan dan completed setelah berakhir. Sesi yang tidak pernah terhubung meninggalkan transkripsi berstatus canceled.
  • Transkripsi memiliki source: { "platform": "live", "session_id": "lv_…" }. Tidak ada tautan atau file. Dasbor menampilkannya sebagai sesi langsung.
  • Setiap baris menjadi satu segmen, dengan indeks yang sama dengan id baris. Baca transkrip sebagai JSON, teks, SRT, atau VTT seperti transkripsi lain: lihat referensi API.
  • Terjemahan langsung ikut tersimpan. Bacalah dengan parameter translation, seperti dijelaskan di Terjemahan.
  • Tambahkan bahasa terjemahan lain nanti dengan POST /v1/transcriptions/:id/translations setelah transkripsi berstatus completed. Lihat Terjemahan.

Dengan save: false, tidak ada yang disimpan setelah sesi berakhir: tidak ada transkripsi dan transcription_id bernilai null. Anda tetap menerima setiap baris lewat socket dan tagihan biasa tetap berlaku.

Keamanan

  • Token yang Anda terima saat membuat sesi hanya berlaku sekali dan kedaluwarsa dalam 60 detik. Token dikirim sebagai subprotokol WebSocket, bukan di URL, sehingga tidak masuk log akses. Token yang bocor tidak berguna setelah dipakai atau kedaluwarsa.
  • Gunakan kunci API hanya dari server yang Anda kendalikan. Jangan pernah menaruh kunci API di halaman web atau ekstensi.
  • Di browser atau ekstensi, masukkan pengguna dengan OAuth dan teruskan access token OAuth ke getAccessToken pada createLiveClient. Token memerlukan scope transcriptions:write untuk memulai sesi. Access token OAuth kedaluwarsa setelah 1 jam, dan setiap kelanjutan sesi meminta token baru dari getAccessToken.
  • Server Anda juga bisa membuat sesi dengan kunci API lalu hanya memberikan websocket_url dan token ke browser. Klien kemudian terhubung langsung. Klien tidak bisa melanjutkan sesi tanpa token baru dari Anda.

Pembaruan terakhir 3 November 2026