Async transcription API

Transcription asynchrone pour les audios et vidéos longs

Un modèle de job assumé : 202 immédiat, id à conserver, statuts explicites, polling, refus typés en 402 et relance sur le même job. Le bon outil dès que le média est long.

requête
# 1. Créer le job — réponse immédiate, même pour 2 h d'audio
curl -i -X POST https://api.techtuel.com/v1/transcriptions \
  -H "Authorization: Bearer $TECHTUEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "audio_url": "https://cdn.example.com/conference-integrale.mp3" }'
# HTTP/1.1 202 Accepted
# { "id": "job_1f88", "status": "processing", "minutes": 0 }

# 2. Poller jusqu'à un état terminal (completed ou failed —
#    processing et claimed veulent tous deux dire "en cours")
until curl -s https://api.techtuel.com/v1/transcriptions/job_1f88 \
  -H "Authorization: Bearer $TECHTUEL_API_KEY" \
  | jq -e '.status == "completed" or .status == "failed"' > /dev/null; do
  sleep 10
done

# 3. Vérifier l'enveloppe restante avant un lot
curl https://api.techtuel.com/v1/usage \
  -H "Authorization: Bearer $TECHTUEL_API_KEY"
réponse
{
  "id": "job_1f88",
  "status": "completed",
  "title": "Conférence intégrale — journée du 12 mai",
  "language": "fr",
  "minutes": 118.3,
  "created_at": "2026-07-21T09:30:00Z",
  "transcript": "Bonjour à toutes et à tous…",
  "segments": [
    { "start_seconds": 0, "text": "Bonjour à toutes et à tous" }
  ],
  "error": ""
}

// Refus de quota, sur le POST :
// HTTP/1.1 402
// { "message": "monthly credits exhausted", "reason": "quota_exceeded" }

Transcrire deux heures d’audio ne peut pas tenir dans une requête HTTP : timeouts de load balancer, connexions coupées à 95 % du travail, reprise impossible parce que le seul état vivait dans une socket. C’est précisément là que le modèle de job est le bon outil — et c’est pour cette raison que POST /v1/transcribe, l’endpoint synchrone qui renvoie la transcription directement, bascule lui-même sur un 202 avec un id de job dès que la fenêtre d’attente est dépassée. Court : une requête suffit. Long : le job prend le relais.

Le cycle. POST /v1/transcriptions répond 202 avec un id et status: processing. Le job passe ensuite par claimed quand un worker le prend en charge, puis termine en completed ou failed — seuls ces deux derniers sont terminaux. Vous interrogez GET /v1/transcriptions/{id} pour lire le statut ; sur un completed, la même réponse porte déjà transcript et segments. Cadence raisonnable : toutes les cinq à dix secondes sur un job actif, plus espacé sur un traitement de fond, dans la limite de 120 requêtes par minute et par clé.

Soyons clairs sur le mécanisme : il n’y a pas de webhook. Le suivi se fait par polling, ou par l’attente que POST /v1/transcribe fait pour vous côté serveur. C’est une contrainte, mais elle a une contrepartie utile — vous n’avez aucun endpoint public à exposer, aucune signature à vérifier, aucun rejeu à dédupliquer, et un worker qui redémarre reprend simplement là où il en était puisque le job id est persistant.

Les refus sont typés. Quand votre quota est épuisé ou qu’un paiement a échoué, l’API répond 402 avec un corps { message, reason }, où reason vaut quota_exceeded ou payment_failed. C’est le discriminant qui vous permet de mettre en pause votre file d’attente dans un cas et d’alerter la facturation dans l’autre, sans parser un message. GET /v1/usage vous donne l’état en amont — credits_used, credits_limit, rate_per_min, renews_at, billing_state — ce qui permet de vérifier l’enveloppe restante avant de lancer un lot. Enfin, un job failed se relance avec POST /v1/transcriptions/{id}/retry, sur le même identifiant.

Pourquoi cette API

Aucun timeout à gérer

Le 202 est immédiat, quelle que soit la durée du média. Votre requête HTTP ne reste jamais ouverte pendant le traitement.

Refus 402 exploitables

reason vaut quota_exceeded ou payment_failed. Votre file peut faire la différence entre « attendre le renouvellement » et « alerter la facturation ».

Relance et inventaire

POST /{id}/retry rejoue un job en échec sans changer d’identifiant, et GET /v1/transcriptions pagine vos jobs pour réconcilier après un incident.

Tarifs lisibles

Gratuit100 crédits/mois (≈ 50 min), sans carte bancaire
Pro2000 crédits/mois (≈ 1000 min), 120 req/min pour paralléliser

Questions fréquentes

Existe-t-il des webhooks de fin de traitement ?+

Non. Le suivi se fait exclusivement par polling sur GET /v1/transcriptions/{id}. En contrepartie, vous n’avez ni endpoint public à exposer, ni signature à vérifier, ni rejeu à dédupliquer.

Quels sont les statuts possibles d’un job ?+

processing à la création, claimed quand un worker le prend en charge, puis completed ou failed. Sur un échec, le champ error donne la raison.

À quelle fréquence interroger le job ?+

Toutes les cinq à dix secondes sur un job actif suffit largement ; espacez davantage pour un traitement de fond. La limite est de 120 requêtes par minute et par clé sur le plan Pro.

Comment réagir à une réponse 402 ?+

Lisez le champ reason. quota_exceeded signifie que l’enveloppe mensuelle est épuisée : mettez la file en pause jusqu’à renews_at. payment_failed relève de la facturation et demande une action sur le moyen de paiement.

Peut-on traiter plusieurs médias en parallèle ?+

Oui. Créez autant de jobs que nécessaire dans la limite de débit, conservez leurs id, puis repassez sur ceux qui sont encore en cours. GET /v1/transcriptions les pagine avec page, per_page et api_key_id.

Autres façons d'intégrer l'API

Essai gratuit, sans carte bancaire

Générez une clé API et transcrivez votre première source en moins d'une minute. Quota mensuel gratuit pour tester en conditions réelles.

Commencer avec l'API