
Développer avec une API de transcription : première intégration
Summarize this article with:
L'intégration en cinq étapes
Vous pouvez ajouter la transcription à n'importe quel backend en moins d'une heure : obtenez une clé API, envoyez l'audio en POST (par upload de fichier ou par URL), interrogez ou recevez un webhook à l'achèvement, récupérez le résultat et exportez-le dans le format dont vous avez besoin. Les modèles présentés ici sont illustrés avec l'API ConvertAudioToText, mais le schéma « soumettre puis interroger » est standard chez tous les fournisseurs de transcription asynchrone. Si vous hésitez encore entre plusieurs fournisseurs, consultez d'abord le comparatif des API de transcription 2026.
Les cinq étapes sont : s'authentifier, soumettre une tâche, récupérer le résultat, gérer les erreurs et exporter. Chaque section ci-dessous couvre une étape avec du code prêt à exécuter.
Étape 1 : Obtenir une clé API
L'accès à l'API sur ConvertAudioToText nécessite l'abonnement Business. Dans le tableau de bord, allez dans Paramètres, puis Clés API, puis créez une nouvelle clé. Donnez-lui un nom descriptif lié à l'intégration ("production-backend", "staging-ingest"). La clé n'est affichée qu'une seule fois, copiez-la donc immédiatement.
Format de la clé : ck_live_ suivi de 64 caractères hexadécimaux. Traitez-la comme un mot de passe. Stockez-la dans une variable d'environnement, jamais dans votre gestionnaire de versions.
Chaque requête utilise Authorization: Bearer <key> :
curl https://api.convertaudiototext.com/api/v1/result/some-job-id \
-H "Authorization: Bearer ck_live_..."
En Node.js :
const headers = { 'Authorization': `Bearer ${process.env.CATT_API_KEY}` };
En Python :
headers = {'Authorization': f'Bearer {os.environ["CATT_API_KEY"]}'}
Étape 2 : Soumettre une tâche de transcription
Le point de terminaison est POST /api/v1/transcribe. Il renvoie immédiatement un HTTP 201 accompagné d'un job_id ; la transcription elle-même est asynchrone.
Deux voies de soumission existent : l'upload de fichier et l'URL. Elles renvoient la même forme de réponse.
Upload de fichier
Utilisez cette voie lorsque l'audio est local ou lorsque vos utilisateurs vous l'envoient sous forme d'upload multipart.
import FormData from 'form-data';
import { createReadStream } from 'fs';
import fetch from 'node-fetch';
async function submitFileJob(filePath, language = 'en') {
const form = new FormData();
form.append('source', 'upload');
form.append('language', language);
form.append('file', createReadStream(filePath));
const res = await fetch('https://api.convertaudiototext.com/api/v1/transcribe', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.CATT_API_KEY}` },
body: form
});
if (!res.ok) throw new Error(`Échec de la soumission : ${res.status}`);
const { job_id, status } = await res.json();
return { job_id, status };
}
Soumission par URL
Utilisez cette voie lorsque l'audio se trouve déjà dans un stockage cloud (S3, R2, GCS ou toute URL HTTPS publique). Le serveur télécharge à haut débit depuis l'origine, ce qui est plus rapide que de réuploader depuis votre machine.
async function submitURLJob(audioURL, language = 'en') {
const res = await fetch('https://api.convertaudiototext.com/api/v1/transcribe', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CATT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
source: 'url',
input_url: audioURL,
language: language
})
});
if (!res.ok) throw new Error(`Échec de la soumission : ${res.status}`);
const { job_id, status } = await res.json();
return { job_id, status };
}
Les deux renvoient { job_id: "uuid-string", status: "queued" }.

L'outil d'upload audio propulsé par l'API. Le même pipeline de traitement s'exécute que vous utilisiez l'interface web ou l'API.
Étape 3 : Récupérer le résultat
Une tâche terminée est disponible via GET /api/v1/result/{job_id}. Deux approches pour attendre : le polling et les webhooks.
Polling
Interrogez toutes les 5 secondes jusqu'à ce que status soit "completed" ou "failed". Le point de terminaison répond instantanément ; le délai vient entièrement du côté de la transcription.
async function pollForResult(jobId, maxWaitMs = 600000) {
const start = Date.now();
while (Date.now() - start < maxWaitMs) {
const res = await fetch(
`https://api.convertaudiototext.com/api/v1/result/${jobId}`,
{ headers: { 'Authorization': `Bearer ${process.env.CATT_API_KEY}` } }
);
const data = await res.json();
if (data.status === 'completed') return data;
if (data.status === 'failed') throw new Error(data.error || 'Tâche échouée');
await new Promise(r => setTimeout(r, 5000));
}
throw new Error('Délai dépassé en attendant le résultat de la transcription');
}
N'interrogez pas plus vite qu'une fois par seconde et par tâche. La limite globale est de 100 requêtes par minute et par IP ; une boucle serrée sur de nombreuses tâches finira donc par la déclencher.
Webhooks
Pour une meilleure utilisation des ressources à grande échelle, les webhooks remplacent entièrement le polling. Enregistrez une URL de webhook une seule fois :
curl -X POST https://api.convertaudiototext.com/api/v1/dashboard/webhooks \
-H "Authorization: Bearer $CATT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/transcription",
"events": ["job.completed", "job.failed"]
}'
La réponse contient un champ secret. Conservez-le. Le serveur enverra une requête POST à votre URL à chaque événement correspondant. La charge utile ressemble à ceci :
{
"event": "job.completed",
"timestamp": "2026-07-01T14:22:05Z",
"data": {
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"duration": 1842,
"result_url": "https://api.convertaudiototext.com/api/v1/result/550e8400-...",
"completed_at": "2026-07-01T14:22:04Z"
}
}
Vérifiez chaque livraison avec HMAC-SHA256. Le serveur envoie la signature dans X-Webhook-Signature sous la forme sha256=<hex> :
import crypto from 'crypto';
function verifyWebhookSignature(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// Dans votre gestionnaire Express/Fastify :
app.post('/webhooks/transcription', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-webhook-signature'];
if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Signature invalide');
}
const { event, data } = JSON.parse(req.body);
if (event === 'job.completed') {
// récupérer la transcription complète depuis data.result_url
}
res.status(200).end();
});
Les webhooks nécessitent l'abonnement Business et une URL HTTPS publiquement accessible. Pour une comparaison plus approfondie des deux approches, consultez le guide webhook vs polling pour les transcriptions.
Étape 4 : Analyser le résultat
La réponse d'une tâche terminée imbrique la transcription sous une clé transcript. La forme exacte est contrôlée par le formateur côté serveur, mais les champs que vous trouverez toujours sont :
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"language": "en",
"duration": 1842,
"filename": "interview.mp3",
"transcript": {
"text": "Bonjour, bienvenue dans l'émission...",
"summary": "Une interview à propos...",
"confidence": 0.97,
"word_count": 4210,
"timeline": [
{
"speaker": "Intervenant 0",
"text": "Bonjour, bienvenue dans l'émission.",
"start": 0.12,
"end": 1.87
}
],
"topics": [...],
"sentiments": [...]
}
}
Le champ text contient la transcription complète concaténée. Le tableau timeline vous donne les énoncés attribués à chaque intervenant avec leur horodatage. Les champs summary, topics et sentiments sont renseignés pour l'audio en anglais sur les offres incluant les insights IA ; ils seront supprimés ou absents sur l'offre Starter.
Étape 5 : Formats d'export
Téléchargez les fichiers formatés via :
curl "https://api.convertaudiototext.com/api/v1/result/$JOB_ID/srt" \
-H "Authorization: Bearer $CATT_API_KEY" > captions.srt # SRT pour les sous-titres vidéo
curl "https://api.convertaudiototext.com/api/v1/result/$JOB_ID/vtt" \
-H "Authorization: Bearer $CATT_API_KEY" > captions.vtt # WebVTT
curl "https://api.convertaudiototext.com/api/v1/result/$JOB_ID/txt" \
-H "Authorization: Bearer $CATT_API_KEY" > transcript.txt # Texte brut avec étiquettes d'intervenants
curl "https://api.convertaudiototext.com/api/v1/result/$JOB_ID/json" \
-H "Authorization: Bearer $CATT_API_KEY" > transcript.json # JSON structuré
curl "https://api.convertaudiototext.com/api/v1/result/$JOB_ID/docx" \
-H "Authorization: Bearer $CATT_API_KEY" > transcript.docx # DOCX
Tous les points de terminaison d'export nécessitent un abonnement payant. Les requêtes du niveau gratuit renvoient HTTP 402 avec un champ upgrade_url. Pour construire des workflows de sous-titrage à grande échelle, les points de terminaison SRT et VTT fonctionnent bien dans des pipelines par lots.
Gestion des erreurs
Trois catégories d'erreurs à gérer, chacune avec une stratégie de récupération différente.
Les erreurs 4xx viennent de votre bug. Authentification incorrecte (401), champs requis manquants (400), quota épuisé (402) ou limite de débit atteinte (429). Ne réessayez pas sans corriger la requête. Sur un 429, lisez le champ retry_after dans le corps de la réponse.
Les erreurs 5xx sont transitoires. Réessayez avec un backoff exponentiel. La plupart disparaissent en moins de 30 secondes.
Échecs au niveau de la tâche. Une tâche peut être soumise avec succès (HTTP 201) puis échouer plus tard pendant le traitement. status passe alors à "failed" et error indique la raison. Causes fréquentes : audio corrompu, enregistrements silencieux du début à la fin, codecs non pris en charge. Ne relancez la tâche que si la source audio est valide.
async function transcribeWithRetry(audioPath, maxAttempts = 3) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
const { job_id } = await submitFileJob(audioPath);
return await pollForResult(job_id);
} catch (err) {
// 4xx : corriger la requête, ne pas réessayer
if (err.status >= 400 && err.status <= 499) throw err;
// Dernière tentative : abandonner
if (attempt === maxAttempts - 1) throw err;
// 5xx : attendre puis réessayer
const delayMs = 1000 * Math.pow(2, attempt);
await new Promise(r => setTimeout(r, delayMs));
}
}
}
Limites de débit
Les limites qui s'appliquent aux requêtes API authentifiées :
| Couche | Limite | Périmètre |
|---|---|---|
| Globale | 100 requêtes/min | Par adresse IP |
| Tâches de transcription | 10 soumissions/min | Par utilisateur authentifié |
| Upload multipart (appels de signature) | 1000/min | Par IP, plafond distinct |
La limite de tâches de transcription signifie que vous pouvez soumettre jusqu'à 10 tâches par minute, pas 10 simultanées ; les tâches au-delà de ce seuil sont mises en file d'attente côté serveur.
Atteindre l'une de ces limites renvoie HTTP 429 avec retry_after en secondes dans le corps de la réponse.
Un exemple complet et fonctionnel
import { createReadStream } from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';
const API_KEY = process.env.CATT_API_KEY;
const BASE = 'https://api.convertaudiototext.com/api/v1';
async function submit(filePath, language = 'en') {
const form = new FormData();
form.append('source', 'upload');
form.append('language', language);
form.append('file', createReadStream(filePath));
const res = await fetch(`${BASE}/transcribe`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` },
body: form
});
if (!res.ok) throw Object.assign(new Error('Échec de la soumission'), { status: res.status });
return res.json();
}
async function poll(jobId, maxWaitMs = 600000) {
const deadline = Date.now() + maxWaitMs;
while (Date.now() < deadline) {
const res = await fetch(`${BASE}/result/${jobId}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const data = await res.json();
if (data.status === 'completed') return data;
if (data.status === 'failed') throw new Error(data.error || 'Échec de la transcription');
await new Promise(r => setTimeout(r, 5000));
}
throw new Error('Délai dépassé');
}
export async function transcribeFile(filePath, language = 'en') {
const { job_id } = await submit(filePath, language);
const result = await poll(job_id);
return result.transcript?.text ?? '';
}
À partir de là, ajoutez un cache des résultats de transcription pour éviter de retraiter des fichiers identiques, et remplacez le polling par des webhooks dès que vous avez plus de quelques tâches simultanées.
Mon avis : le schéma « soumettre puis interroger » est le même chez tous les grands fournisseurs de transcription asynchrone, si bien que le code client se transfère presque tel quel. Ce qui diffère, ce sont le format de l'en-tête d'authentification, les noms des champs dans la réponse, et le fait que certaines fonctionnalités avancées comme les étiquettes d'intervenants nécessitent un abonnement supérieur. Vérifiez chacun de ces points dans la documentation actuelle du fournisseur avant de passer en production.
Si vous n'avez besoin que d'une transcription propre de temps en temps, sans avoir à gérer de clés API ni de paliers d'abonnement, ConvertAudioToText vous permet d'uploader, de transcrire et de copier votre transcription gratuitement, sans aucune configuration.
Questions fréquentes
Quel abonnement faut-il pour utiliser l'API ?
La création d'une clé API sur ConvertAudioToText nécessite l'abonnement Developer ou Business. Developer inclut 600 minutes par mois ; Business est illimité. Consultez /pricing pour connaître les derniers paliers avant l'achat.
Quelle est la limite de débit pour les tâches de transcription ?
La limite globale est de 100 requêtes par minute et par adresse IP. Les soumissions de tâches de transcription sont en outre plafonnées à 10 tâches par minute et par utilisateur. Atteindre l'une de ces limites renvoie un HTTP 429 avec un en-tête Retry-After.
Polling ou webhooks : lequel choisir ?
Le polling convient aux intégrations à faible volume ou ponctuelles et ne nécessite aucun point de terminaison public. Les webhooks deviennent préférables dès que vous avez plusieurs tâches simultanées : au lieu d'interroger N tâches toutes les quelques secondes, votre serveur reçoit une requête POST par achèvement. Les webhooks nécessitent l'abonnement Business et une URL HTTPS publiquement accessible.
Comment vérifier qu'une charge utile de webhook est authentique ?
Chaque enregistrement de webhook renvoie une chaîne secrète. Lorsque le serveur livre une charge utile, il calcule le HMAC-SHA256 du corps JSON brut à l'aide de ce secret et envoie le résultat dans l'en-tête X-Webhook-Signature sous la forme sha256=hex. Recalculez le même HMAC de votre côté et comparez. Rejetez toute requête où les deux valeurs ne correspondent pas.
Quels formats d'export l'API prend-elle en charge ?
Les tâches terminées peuvent être exportées en SRT, VTT, TXT, JSON, DOCX et PDF via GET /api/v1/result//. Tous les points de terminaison d'export nécessitent un abonnement payant ; les requêtes du niveau gratuit renvoient HTTP 402.
Sources
- Code source backend de ConvertAudioToText :
/backend/internal/api/handlers/transcribe.go,webhook.go,apikey.go,middleware/ratelimit.go,services/apikey/service.go,services/webhook/service.go,services/billing/plans.go(lu directement dans le dépôt, 2026-07-02) - Prise en charge des langues Deepgram : https://developers.deepgram.com/docs/models-languages-overview
- Tarifs et niveaux d'abonnement ConvertAudioToText : https://convertaudiototext.com/pricing
Try transcription free
Convert any audio or video to clean, unwatermarked text — speaker labels, timestamps, and AI summaries included. First 10 minutes free, no account.
Related Articles

Speechmatics Alternative for Non-Developers: Web Transcription Without Code
Speechmatics is genuinely excellent for developers: 50 hours free per month, 56 languages, on-prem deployment. If you need a drag-and-drop web app with flat $9.99/mo pricing instead of an API, here is an honest comparison of the two.

Best Transcription Tools with API Access (2026)
Which transcription SaaS tools actually give you API keys, and on which plan? Verified pricing and plan gates for Descript, Sonix, Fireflies, Happy Scribe, AssemblyAI, and more.