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 si | Choisissez 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 :
| Champ | Valeur par défaut | Règle |
|---|---|---|
language | auto | auto, ou un code à deux lettres pris en charge par la transcription en direct. |
translate_to | aucune | Un code à deux lettres. Une seule langue cible par session. Voir Traduire en direct. |
diarize | false | Identifie les locuteurs. Certaines configurations ne le permettent pas, par exemple avec language: "auto", et répondent 422. Consultez les capacités. |
audio_format | pcm_s16le | La seule valeur. Le champ existe pour pouvoir ajouter d'autres formats plus tard. |
sample_rate | 16000 | Un entier de 8000 à 48000. Mono uniquement. |
save | true | Avec 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
linea un original (text,final) et un objettranslation(language,text,final).translationvautnullquandtranslate_ton'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
| Message | Signification |
|---|---|
| Trame binaire | Audio : 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 reste | Un é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énement | Envoyé quand |
|---|---|
session.started | La connexion a été acceptée. Envoyez de l'audio à partir de maintenant. |
line | Une ligne de sous-titres a été créée ou modifiée. |
usage | Après chaque débit. |
warning | Quelque chose demande de l'attention mais la session continue. |
error | Un problème non fatal, ou la raison d'une fermeture immédiate. |
reconnect | Le serveur est sur le point de redémarrer. Reprenez la session. |
session.ended | La 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 :
code | Signification |
|---|---|
balance_low | Le prochain débit échouerait. La session se termine avec balance_exhausted quand il arrivera. Non envoyé tant que la recharge automatique est active. |
audio_dropped | De 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_soon | Aucun 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 :
code | Fatal | Signification |
|---|---|---|
invalid_message | Non | Une trame texte qui n'est ni finalize ni end. |
invalid_token | Oui | Le token est invalide, expiré ou déjà utilisé. Le socket se ferme avec 4001. |
not_found | Oui | La session n'existe pas. Le socket se ferme avec 4004. |
session_ended | Oui | La 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
| Champ | Signification |
|---|---|
id | Un 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_ms | Début et fin dans le temps audio de la session. Ce temps se poursuit à travers les reconnexions. |
speaker | L'étiquette du locuteur quand diarize est activé, sinon null. Les étiquettes sont les mêmes que dans les transcriptions ordinaires. |
language | La langue détectée ou indiquée de la ligne, ou null si elle n'est pas encore connue. |
text | Le texte original jusqu'ici. |
final | true une fois que le texte original ne changera plus. |
translation | null 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 :
| Motif | Signification |
|---|---|
client_ended | Vous avez envoyé end. |
balance_exhausted | Le débit suivant a échoué. La session se termine à un changement de minute et elle est enregistrée. |
idle_timeout | Aucun audio pendant 5 minutes. |
max_duration | La session est restée connectée 300 minutes. Démarrez-en une nouvelle. |
disconnected | Le client est resté absent plus de 2 minutes sans reprendre. |
upstream_error | Le fournisseur de reconnaissance vocale est tombé en panne. |
internal_error | Une erreur s'est produite sur nos serveurs. |
not_connected | La 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
| Code | Signification |
|---|---|
1000 | Fermeture normale. Elle suit toujours session.ended. |
1011 | Erreur inattendue du serveur. Le serveur récupère la session : reprenez avec un nouveau token. |
1012 | Redémarrage du serveur. Il suit reconnect : reprenez avec un nouveau token. |
4001 | Le token est invalide, expiré ou déjà utilisé. |
4004 | La session est introuvable ou déjà terminée. |
4008 | Violation du protocole : une trame binaire de longueur impaire ou trop volumineuse. |
4010 | Remplacé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.
- Appelez
POST /v1/live/sessions/:id/token. La réponse contienttoken,token_expires_atetwebsocket_url, les mêmes champs qu'à la création de la session. L'appel échoue avec409 session_endedune fois la session terminée. - Ouvrez un nouveau WebSocket avec ce token.
session.startedarrive avecresumed: true.offset_msest 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
rateminutes de solde, arrondies à l'unité supérieure. Le tarif vaut souvent 1 et peut avoir des décimales. Lisez le tarif en direct dansrates.livedeGET /v1/account, dansratedeGET /v1/live/capabilitieset dansratede 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_errorouinternal_erroravant 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'avertissementbalance_lowvient 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
| Free | Monthly | Annual | |
|---|---|---|---|
| Sessions en direct simultanées | 1 | 2 | 3 |
- Une session compte tant qu'elle est
waiting,connectedoudisconnected(dans sa fenêtre de 2 minutes). Au-delà de la limite,POST /v1/live/sessionsrenvoie429 too_many_live_sessionsavecRetry-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 recevezidle_timeout_soonaprè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/sessionsrenvoie503 live_capacity, qui peut être réessayé. AttendezRetry-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.pairsvaut"any"(toute langue détectée vers toute cible), ou une liste d'objets avecfrometto.translation.requires_languagevauttruequand la traduction exige unlanguageexplicite plutôt queauto.- Quand la transcription en direct n'est pas configurée, la réponse est
available: falseavec seulementrate, et la création d'une session renvoie503 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 HTTP | code | Réessayer ? | Quand |
|---|---|---|---|
| 422 | invalid_request | Non | Un champ manque ou est invalide, par exemple une sample_rate hors de la plage 8000 à 48000. |
| 422 | unsupported_language | Non | language n'est pas pris en charge pour la transcription en direct. |
| 422 | unsupported_translation | Non | La langue cible, ou la paire de langues, n'est pas prise en charge. |
| 402 | insufficient_minutes | Non | Votre solde utilisable est inférieur à une minute entamée au tarif actuel. |
| 403 | email_not_verified | Non | Vérifiez d'abord votre adresse e-mail. |
| 429 | too_many_live_sessions | Oui | Les sessions en direct simultanées de votre offre sont toutes utilisées. Attendez Retry-After. |
| 503 | live_capacity | Oui | Toute la capacité en direct est utilisée. Attendez Retry-After (30 secondes). |
| 503 | live_unavailable | Non | La transcription en direct n'est pas disponible pour le moment. |
| 409 | session_ended | Non | POST /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_idest renvoyé à la création de la session. Son statut estlivependant la session etcompletedaprès. Une session qui ne s'est jamais connectée laisse une transcriptioncanceled.- 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'
idde 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 transcriptioncompleted. 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 à
getAccessTokendecreateLiveClient. Le token a besoin du scopetranscriptions:writepour 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_urlettoken. 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