DocumentationTranscription en direct

Transcription en direct

Envoyez l'audio du micro ou d'un onglet à transcript1 par WebSocket et recevez des lignes de sous-titres, avec traduction en temps réel en option, pendant que les gens parlent.

La transcription en direct transforme un flux audio en lignes de sous-titres pendant que les gens parlent encore. Votre client envoie de l'audio PCM brut par WebSocket, et transcript1 renvoie des lignes qui commencent par une version provisoire avant de devenir définitives. Ajoutez translate_to et chaque ligne arrive aussi avec sa traduction. À la fin de la session, le résultat est enregistré comme une transcription ordinaire.

Il n'existe pas d'offre distincte pour le direct : la transcription en direct utilise le même solde de minutes que le reste. La section Facturation explique comment le temps de connexion est compté.

Quand choisir le direct

Choisissez le direct siChoisissez une transcription classique si
L'audio est encore en cours de production : un appel, une conférence, un live, une vidéo que vous regardez.Vous avez un lien ou un fichier terminé.
Il vous faut des sous-titres une à deux secondes après la parole.Vous voulez la meilleure précision et pouvez attendre le résultat.
Vous voulez une traduction en temps réel à côté de chaque ligne.Vous voulez traduire une transcription terminée, ou dans plusieurs langues.

Le direct n'accepte que de l'audio, en PCM brut. Il n'accepte ni liens vidéo, ni fichiers importés, ni WebM, Opus ou MP3. Capturez l'audio dans votre client et convertissez-le d'abord en PCM. La section Capturer l'audio dans un navigateur montre comment faire.

Démarrage rapide avec le SDK

Installez le SDK 1.5.0 ou une version plus récente : npm i @transcript1/sdk@latest. t1.live.start crée la session, se connecte et se résout une fois la session démarrée : vous pouvez donc envoyer de l'audio tout de suite.

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

Les lignes se mettent à jour en place. Remplacez une ligne que vous avez déjà quand une autre avec le même id arrive, ou lisez-les toutes depuis live.lines. end() termine la session, attend les dernières lignes et enregistre la transcription. Toutes les méthodes et tous les événements sont décrits dans SDK Node.js.

Démarrage rapide avec un WebSocket brut

Sans le SDK, il y a deux étapes : créer une session en HTTPS, puis ouvrir le WebSocket avec le token à usage unique reçu en retour.

Créer une session

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

L'API répond 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 vaut null quand save est false. Le token est à usage unique et expire après 60 secondes : connectez-vous tout de suite. rate est le nombre de minutes de solde débitées par minute entamée de cette session ; voir Facturation.

Le corps de la requête accepte ces champs. Tous sont facultatifs, et le scope requis est transcriptions:write :

ChampValeur par défautRègle
languageautoauto, ou un code à deux lettres pris en charge par la transcription en direct.
translate_toaucuneUn code à deux lettres. Une seule langue cible par session. Voir Traduire en direct.
diarizefalseIdentifie les locuteurs. Certaines configurations ne le permettent pas, par exemple avec language: "auto", et répondent 422. Consultez les capacités.
audio_formatpcm_s16leLa seule valeur. Le champ existe pour pouvoir ajouter d'autres formats plus tard.
sample_rate16000Un entier de 8000 à 48000. Mono uniquement.
savetrueAvec false, rien n'est conservé à la fin de la session. Voir Transcriptions enregistrées.

Se connecter et diffuser

Ouvrez le WebSocket avec le token comme second sous-protocole. Cela fonctionne dans les navigateurs et sous Node 22+ sans en-têtes personnalisés. Attendez session.started avant d'envoyer de l'audio : les trames binaires envoyées plus tôt sont ignorées, et vous recevez un avertissement 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 n'a pas de WebSocket intégré : utilisez le paquet ws, qui a la même forme new WebSocket(url, protocols).

Pour un token valide, le serveur répond avec le sous-protocole t1-live et rien d'autre. Un mauvais token ne fait jamais échouer la poignée de main : le socket s'ouvre, vous recevez un événement error et le socket se ferme avec un code 4xxx, de sorte qu'un navigateur affiche la vraie raison plutôt qu'un 1006 générique. Voir Codes de fermeture.

Capturer l'audio dans un navigateur

L'audio en direct doit être du PCM mono signé sur 16 bits, little-endian, à la sample_rate de la session. Les navigateurs fournissent des échantillons en virgule flottante : convertissez-les dans un AudioWorklet. Cet extrait capture le micro en PCM 16 kHz par blocs de 100 ms et l'envoie avec le point d'entrée navigateur du SDK. getAccessToken renvoie un token d'accès OAuth ; ne mettez jamais de clé API dans un navigateur. Voir Sécurité.

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

Le worklet est écrit pour 16 kHz. Si le contexte tourne à une autre fréquence, les blocs ne durent plus 100 ms, mais le PCM reste correct puisque sampleRate correspond au contexte. Pour capturer le son d'un onglet ou d'une vidéo plutôt que le micro, créez le MediaStream avec getDisplayMedia ou à partir du captureStream() d'un élément média, puis branchez-le de la même façon.

Traduire en direct

Ajoutez translate_to à la session et transcript1 traduit chaque ligne au fil de la parole.

  • Une seule langue cible par session. Ajoutez ensuite d'autres langues à la transcription enregistrée avec l'endpoint de traduction.
  • Chaque line a un original (text, final) et un objet translation (language, text, final). translation vaut null quand translate_to n'est pas défini.
  • L'original et la traduction deviennent définitifs indépendamment : une ligne peut avoir un original définitif alors que sa traduction change encore. Affichez une ligne comme définitive quand les deux le sont.
  • Une ligne déjà dans la langue cible utilise son propre texte comme traduction, et elle est définitive dès qu'elle se clôt.
  • Une ligne se clôt quand le locuteur marque une pause, quand le locuteur change, quand une pause entre deux mots dépasse 0.9 seconde, quand la ligne atteint deux rangées de sous-titres (84 caractères) ou 15 secondes, ou quand vous envoyez finalize. Avec la traduction activée, une ligne peut mettre environ 3 secondes de plus à se clore, le temps que sa traduction arrive. Dans ce cas, la traduction peut rester ouverte (final: false) et continuer à s'allonger après que l'original est devenu définitif.
  • La traduction est gratuite. Elle ne consomme aucune minute.

Les langues cibles et les paires de langues disponibles dépendent du fournisseur de reconnaissance vocale en direct. Lisez les capacités au lieu de coder des règles en dur. Une cible non prise en charge renvoie 422 unsupported_translation. Par exemple, un fournisseur peut exiger un language explicite plutôt que auto, ou n'autoriser que les paires incluant l'anglais.

Protocole WebSocket

Connexion

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

Le token voyage comme sous-protocole WebSocket. Il n'apparaît jamais dans une URL ni dans un journal d'accès. N'envoyez pas d'en-tête Authorization : le token tient lieu d'identifiant. Le serveur envoie un ping toutes les 30 secondes ; les navigateurs et le paquet ws répondent automatiquement. Un socket qui n'envoie aucun pong pendant 60 secondes est coupé.

Une connexion valide à une session qui a déjà un socket remplace l'ancien. Voir Reprise et remplacement.

Messages du client

MessageSignification
Trame binaireAudio : PCM s16le mono à la sample_rate de la session. Chaque trame a une longueur paire et fait au plus 256 Ko. Environ 100 ms par trame, c'est une bonne taille.
{"type":"finalize"}Clôt tout de suite la ligne en cours, par exemple quand la vidéo est mise en pause.
{"type":"end"}Termine la session et l'enregistre. Le serveur répond session.ended et ferme le socket.
Tout le resteUn événement error non fatal avec le code invalid_message.

Une trame de longueur impaire ou trop volumineuse est une violation du protocole et ferme le socket avec 4008.

Commencez à envoyer de l'audio après session.started. Un client qui envoie l'audio plus vite que le temps réel paie la durée de l'audio plutôt que le temps de connexion (voir Facturation) : envoyez donc au rythme où l'audio est produit.

Événements du serveur

Chaque événement est une trame texte JSON avec un type.

ÉvénementEnvoyé quand
session.startedLa connexion a été acceptée. Envoyez de l'audio à partir de maintenant.
lineUne ligne de sous-titres a été créée ou modifiée.
usageAprès chaque débit.
warningQuelque chose demande de l'attention mais la session continue.
errorUn problème non fatal, ou la raison d'une fermeture immédiate.
reconnectLe serveur est sur le point de redémarrer. Reprenez la session.
session.endedLa session est terminée et enregistrée. C'est le dernier événement avant une fermeture normale.

session.started indique s'il s'agit d'une reprise et quelle quantité d'audio la session a déjà traitée :

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

line porte l'état complet et actuel d'une ligne : remplacez donc la ligne que vous avez avec le même id. Voir L'objet ligne.

{
  "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 est envoyé après chaque débit, avec le temps de connexion, la durée de l'audio, les minutes de solde débitées jusqu'ici et les minutes qu'il vous reste :

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

warning contient un code :

codeSignification
balance_lowLe prochain débit échouerait. La session se termine avec balance_exhausted quand il arrivera. Non envoyé tant que la recharge automatique est active.
audio_droppedDe l'audio est arrivé avant que la session soit prête, ou trop d'audio est arrivé pendant la connexion au fournisseur vocal. L'audio le plus ancien a été abandonné.
idle_timeout_soonAucun audio depuis 4 minutes. La session se termine après 5 minutes sans audio. Envoyez de l'audio pour la conserver.
{ "type": "warning", "code": "idle_timeout_soon" }

error contient un code et un message. Ces codes peuvent arriver sur un socket en direct :

codeFatalSignification
invalid_messageNonUne trame texte qui n'est ni finalize ni end.
invalid_tokenOuiLe token est invalide, expiré ou déjà utilisé. Le socket se ferme avec 4001.
not_foundOuiLa session n'existe pas. Le socket se ferme avec 4004.
session_endedOuiLa session est déjà terminée. Le socket se ferme avec 4004.
{ "type": "error", "code": "invalid_message", "message": "Expected {\"type\":\"finalize\"} or {\"type\":\"end\"}" }

reconnect arrive avant que le serveur ferme le socket avec 1012, par exemple lors d'un déploiement. Récupérez un nouveau token et reprenez.

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

session.ended est le dernier événement de chaque session. Les chiffres sont les totaux définitifs :

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

L'objet ligne

ChampSignification
idUn numéro qui commence à 0 et augmente de un à chaque ligne. C'est l'indice du segment dans la transcription enregistrée.
start_ms, end_msDébut et fin dans le temps audio de la session. Ce temps se poursuit à travers les reconnexions.
speakerL'étiquette du locuteur quand diarize est activé, sinon null. Les étiquettes sont les mêmes que dans les transcriptions ordinaires.
languageLa langue détectée ou indiquée de la ligne, ou null si elle n'est pas encore connue.
textLe texte original jusqu'ici.
finaltrue une fois que le texte original ne changera plus.
translationnull sans translate_to, sinon language, text et final.

Affichez les lignes avec final: false dans un style plus clair : leur texte peut encore changer. Le texte d'une ligne avec final: true ne change plus jamais, et une ligne définitive n'est jamais supprimée.

Le SDK utilise camelCase pour les champs de ligne : startMs, endMs.

Motifs de fin

session.ended et GET /v1/live/sessions/:id donnent un end_reason :

MotifSignification
client_endedVous avez envoyé end.
balance_exhaustedLe débit suivant a échoué. La session se termine à un changement de minute et elle est enregistrée.
idle_timeoutAucun audio pendant 5 minutes.
max_durationLa session est restée connectée 300 minutes. Démarrez-en une nouvelle.
disconnectedLe client est resté absent plus de 2 minutes sans reprendre.
upstream_errorLe fournisseur de reconnaissance vocale est tombé en panne.
internal_errorUne erreur s'est produite sur nos serveurs.
not_connectedLa session ne s'est jamais connectée dans les 5 minutes. Elle n'est jamais facturée et n'est visible que par GET.

Codes de fermeture

CodeSignification
1000Fermeture normale. Elle suit toujours session.ended.
1011Erreur inattendue du serveur. Le serveur récupère la session : reprenez avec un nouveau token.
1012Redémarrage du serveur. Il suit reconnect : reprenez avec un nouveau token.
4001Le token est invalide, expiré ou déjà utilisé.
4004La session est introuvable ou déjà terminée.
4008Violation du protocole : une trame binaire de longueur impaire ou trop volumineuse.
4010Remplacée par une connexion plus récente à la même session.

Pendant le redémarrage de l'API, une nouvelle requête WebSocket peut recevoir un HTTP 503. Réessayez dans un instant.

Reprise et remplacement

Une session survit à une coupure réseau, à un déploiement de l'API et à un plantage. Pendant 2 minutes après une coupure, elle vous attend ; ensuite elle se termine en disconnected et elle est enregistrée.

  1. Appelez POST /v1/live/sessions/:id/token. La réponse contient token, token_expires_at et websocket_url, les mêmes champs qu'à la création de la session. L'appel échoue avec 409 session_ended une fois la session terminée.
  2. Ouvrez un nouveau WebSocket avec ce token.
  3. session.started arrive avec resumed: true. offset_ms est la quantité d'audio déjà traitée par la session : continuez avec l'audio à partir de ce point. Les identifiants de ligne continuent.

Les lignes déjà définitives sont conservées. La partie en cours au moment de la coupure est perdue : renvoyez donc quelques secondes d'audio à partir de offset_ms si vous les gardez en mémoire tampon. Les interruptions pendant la reconnexion ne sont pas facturées.

Le remplacement passe par le même appel. Si le serveur croit encore qu'un socket est ouvert, une nouvelle connexion valide le remplace, et l'ancien socket est fermé avec 4010 une fois ses lignes enregistrées. La limite de sessions simultanées ne bloque jamais une reprise.

Le SDK fait tout cela pour vous : lors d'une coupure ou d'un événement reconnect, il récupère un token et se reconnecte avec un délai croissant de 0.5 à 8 secondes pendant 2 minutes au maximum, et il renvoie les 10 dernières secondes d'audio envoyées pendant la coupure.

Facturation

La transcription en direct puise dans le même solde de minutes que les transcriptions classiques.

  • Le temps de connexion est facturé, depuis l'acceptation du socket jusqu'à sa fermeture. Le silence et une vidéo en pause comptent. Le temps entre une coupure et la reprise ne compte pas.
  • Par minute entamée, minimum 1. La première minute est débitée à l'acceptation de la première connexion, et chaque minute suivante dès qu'elle commence.
  • Plus vite que le temps réel, c'est la durée de l'audio qui est facturée. Si l'audio que vous envoyez dure plus longtemps que la connexion, la durée de l'audio est facturée à la place.
  • Le tarif se lit dans l'API. Une minute entamée coûte rate minutes de solde, arrondies à l'unité supérieure. Le tarif vaut souvent 1 et peut avoir des décimales. Lisez le tarif en direct dans rates.live de GET /v1/account, dans rate de GET /v1/live/capabilities et dans rate de la session que vous créez. Le tarif d'une session reste fixe une fois la session créée.
  • La traduction est gratuite.
  • Jamais connectée, jamais facturée. Une session qui ne se connecte pas dans les 5 minutes se termine en not_connected.
  • Les échecs sont remboursés. Si une session se termine par upstream_error ou internal_error avant d'avoir produit une seule ligne, tous les débits sont remboursés. Une session vide à cause du silence est facturée et enregistrée vide.
  • Quand le solde est épuisé et que la recharge automatique est active, transcript1 débite votre carte enregistrée pendant que la session continue de diffuser, et la session se poursuit. Si la recharge automatique est désactivée ou en pause, ou si le débit échoue, la session se finalise, s'enregistre et se termine par balance_exhausted à un changement de minute. L'avertissement balance_low vient d'abord, sauf si la recharge automatique est active.

La création d'une session renvoie 402 insufficient_minutes quand votre solde utilisable est inférieur à une minute entamée au tarif actuel. Si la recharge automatique est active, transcript1 tente d'abord une recharge. Voir Facturation et limites.

Limites

FreeMonthlyAnnual
Sessions en direct simultanées123
  • Une session compte tant qu'elle est waiting, connected ou disconnected (dans sa fenêtre de 2 minutes). Au-delà de la limite, POST /v1/live/sessions renvoie 429 too_many_live_sessions avec Retry-After: 30.
  • Les sessions en direct ne comptent pas dans la limite de transcriptions actives.
  • Une session dure au maximum 300 minutes de temps de connexion. Elle se termine ensuite avec max_duration.
  • Une session sans audio pendant 5 minutes se termine avec idle_timeout ; vous recevez idle_timeout_soon après 4 minutes. Un flux en pause continue de facturer du temps de connexion et compte comme inactif : terminez donc la session si la pause est longue.
  • transcript1 limite l'ensemble des sessions en direct. Quand elles sont toutes utilisées, POST /v1/live/sessions renvoie 503 live_capacity, qui peut être réessayé. Attendez Retry-After (30 secondes) et réessayez. Cette vérification n'a lieu qu'à la création d'une session, jamais en cours de route.
  • La création de sessions et la récupération de tokens comptent dans vos requêtes par minute.
  • L'audio est uniquement du PCM brut : pcm_s16le, mono, de 8000 à 48000 Hz.

Capacités

GET /v1/live/capabilities décrit ce que la transcription en direct prend en charge à l'instant, pour que les clients n'aient jamais à coder en dur les règles du fournisseur. Le scope requis est 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
}

Les listes sont abrégées ici. Lisez-les depuis l'API.

  • translation.pairs vaut "any" (toute langue détectée vers toute cible), ou une liste d'objets avec from et to.
  • translation.requires_language vaut true quand la traduction exige un language explicite plutôt que auto.
  • Quand la transcription en direct n'est pas configurée, la réponse est available: false avec seulement rate, et la création d'une session renvoie 503 live_unavailable.

Avec le SDK : await t1.live.capabilities().

Consulter une session

GET /v1/live/sessions/:id renvoie l'état d'une session. Le scope requis est 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 vaut waiting, connected, disconnected ou ended. end_reason vaut null tant que la session n'est pas terminée. Avec le SDK : await t1.live.get(id).

Erreurs

Les erreurs de requête utilisent l'enveloppe d'erreur habituelle. Voici celles que renvoient POST /v1/live/sessions et ses endpoints voisins :

Statut HTTPcodeRéessayer ?Quand
422invalid_requestNonUn champ manque ou est invalide, par exemple une sample_rate hors de la plage 8000 à 48000.
422unsupported_languageNonlanguage n'est pas pris en charge pour la transcription en direct.
422unsupported_translationNonLa langue cible, ou la paire de langues, n'est pas prise en charge.
402insufficient_minutesNonVotre solde utilisable est inférieur à une minute entamée au tarif actuel.
403email_not_verifiedNonVérifiez d'abord votre adresse e-mail.
429too_many_live_sessionsOuiLes sessions en direct simultanées de votre offre sont toutes utilisées. Attendez Retry-After.
503live_capacityOuiToute la capacité en direct est utilisée. Attendez Retry-After (30 secondes).
503live_unavailableNonLa transcription en direct n'est pas disponible pour le moment.
409session_endedNonPOST /v1/live/sessions/:id/token pour une session déjà terminée.

Les problèmes sur le socket arrivent sous forme d'événements error et de codes de fermeture.

Transcriptions enregistrées

Avec save: true (la valeur par défaut), la session est enregistrée comme une transcription ordinaire à sa fin. L'audio n'est jamais stocké.

  • transcription_id est renvoyé à la création de la session. Son statut est live pendant la session et completed après. Une session qui ne s'est jamais connectée laisse une transcription canceled.
  • La transcription a source: { "platform": "live", "session_id": "lv_…" }. Il n'y a ni lien ni fichier. Le tableau de bord la liste comme une session en direct.
  • Chaque ligne devient un segment, avec le même indice que l'id de la ligne. Lisez la transcription en JSON, texte, SRT ou VTT comme n'importe quelle autre : voir la référence de l'API.
  • La traduction en direct est enregistrée avec elle. Lisez-la avec le paramètre translation, comme expliqué dans Traduction.
  • Ajoutez d'autres langues de traduction plus tard avec POST /v1/transcriptions/:id/translations, une fois la transcription completed. Voir Traduction.

Avec save: false, rien n'est conservé à la fin de la session : il n'y a pas de transcription et transcription_id vaut null. Vous recevez quand même chaque ligne sur le socket, et la facturation habituelle s'applique.

Sécurité

  • Le token que vous obtenez à la création d'une session est à usage unique et expire après 60 secondes. Il est envoyé comme sous-protocole WebSocket, pas dans l'URL, donc il reste hors des journaux d'accès. Un token qui fuite est inutile une fois utilisé ou expiré.
  • N'utilisez une clé API que depuis un serveur que vous contrôlez. Ne mettez jamais de clé API dans une page web ou une extension.
  • Dans un navigateur ou une extension, connectez les utilisateurs avec OAuth et passez le token d'accès OAuth à getAccessToken de createLiveClient. Le token a besoin du scope transcriptions:write pour démarrer des sessions. Les tokens d'accès OAuth expirent après 1 heure, et chaque reprise redemande un token neuf à getAccessToken.
  • Votre serveur peut aussi créer la session avec sa clé API et ne transmettre au navigateur que websocket_url et token. Le client se connecte alors directement. Il ne peut pas reprendre la session sans un nouveau token de votre part.

Dernière mise à jour 3 novembre 2026