DocumentationDocumentation API
Documentation API
Retrouvez les endpoints /v1, leurs paramètres et des exemples d'appels. La spécification OpenAPI est disponible en JSON et en YAML.
Introduction
https://api.transcript1.com/v1Utilisez https://api.transcript1.com/v1 comme URL de base pour vos appels API.
- Les appels et les réponses utilisent un corps JSON, avec des champs en
snake_case. - Les dates suivent ISO 8601 en UTC :
2026-10-13T09:30:00.000Z, par exemple. - Les durées et les repères temporels des transcriptions sont en secondes.
- Le format des erreurs ne change pas d'un endpoint à l'autre. Consultez Erreurs pour sa structure.
- Après un appel authentifié, les en-têtes
X-RateLimit-LimitetX-RateLimit-Remainingindiquent votre limite et les requêtes encore disponibles. La page Facturation et limites donne les plafonds par offre. - Avec
source=auto, nous cherchons d'abord des sous-titres exploitables dans la langue d'origine sur YouTube, X, TikTok, Bluesky, Dailymotion et LinkedIn. S'il n'y en a pas, nous transcrivons l'audio. Le modesource=captions(sous-titres uniquement) ne télécharge pas l'audio et ne lance jamais le STT : sans piste exploitable, il renvoieno_captions. Pour passer directement à l'audio, choisissezsource=sttou demandez l'identification des locuteurs. Consultez les possibilités de chaque source pour les restrictions d'accès et la disponibilité des temps par segment ou par mot.
Pour vos outils, récupérez la spécification OpenAPI dans le format de votre choix :
Authentification
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"Ajoutez votre clé API ou votre token OAuth à chaque appel avec l'en-tête Authorization: Bearer <token>.
- Clé API. Son préfixe est
t1_. Créez votre clé dans « API keys » pour accéder à tous les endpoints. - Token d'accès OAuth. Son préfixe est
t1o_. Claude, ChatGPT et les autres clients MCP en reçoivent un lors de la connexion. Il porte les scopestranscriptions:readettranscriptions:write.
| Scope | Appels autorisés |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload et GET /v1/account |
transcriptions:write | POST /v1/transcriptions, DELETE /v1/transcriptions/:id et POST /v1/transcriptions/:id/upload/complete |
- Si le token n'a pas le scope nécessaire, l'API répond
403 insufficient_scope. - Sans clé ou token valide, elle répond
401 unauthorized.
Pour envoyer les blocs d'un fichier, utilisez plutôt X-Upload-Token sur PUT /v1/transcriptions/:id/upload/chunks/:index. Vous recevez ce token à la création de l'upload. La page Importer des fichiers décrit les étapes.
Idempotence
curl -X POST https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Idempotency-Key: 5f1c2b0e-8d4a-4c3e-9b7a-2e6f1d0c9a8b" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'Ajoutez Idempotency-Key à vos appels POST /v1/transcriptions pour pouvoir les renvoyer sans créer de doublon.
Choisissez une clé de 1 à 255 caractères et placez-la dans cet en-tête HTTP, jamais dans les paramètres de l'URL.
- Si vous renvoyez la même clé avec les mêmes paramètres, vous retrouvez la transcription d'origine sans consommer de nouvelles minutes.
- Si vous gardez la clé mais changez les paramètres, l'API répond
409 idempotency_conflict. - Pour un upload en blocs, renvoyer l'appel de création avec cette même clé génère un nouveau token d'upload.
Erreurs
{
"error": {
"code": "insufficient_minutes",
"message": "Not enough minutes",
"retryable": false,
"action_url": "https://transcript1.com/dashboard/billing",
"minutes_needed": 20,
"minutes_remaining": 3
}
}- Si l'API refuse votre appel, vous recevez une erreur de requête.
- Si elle accepte la transcription mais que le traitement échoue ensuite, la transcription passe au
statusfailed.
Lire une réponse d'erreur
Quand l'API refuse un appel /v1, la réponse contient un objet error. Vous y trouverez code, message et retryable.
- Dans votre code, choisissez l'action à effectuer à partir de
code. - Pour expliquer le problème à l'utilisateur, affichez
message. Ne vous basez pas sur son texte pour votre logique : la formulation peut évoluer. - Si
retryablevauttrue, vous pouvez retenter le même appel plus tard.
Selon l'erreur, d'autres champs complètent cet objet au même niveau que retryable :
| Champ | Code concerné | Informations fournies |
|---|---|---|
action_url | insufficient_minutes | Lien pour souscrire une offre ou acheter une recharge. |
minutes_needed, minutes_remaining | insufficient_minutes | Minutes nécessaires pour cet appel (null si ce nombre n'est pas encore connu) et solde disponible. |
supported_platforms | unsupported_platform | Liste des plateformes acceptées : ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Index des blocs à envoyer de nouveau. |
max_bytes | media_too_large | Taille maximale des fichiers pour votre compte, en octets. |
params | invalid_request | Pour les erreurs de validation du corps ou des paramètres d'URL, détail du problème pour chaque champ concerné. |
Quand l'API refuse un appel
| Statut HTTP | code | Peut réussir sans correction ? | Cause et action à effectuer |
|---|---|---|---|
| 400, 422 | invalid_request | Non | Il manque un paramètre ou un champ, ou sa valeur n'est pas valide. Vérifiez notamment les combinaisons interdites : diarize avec source: "captions", ou reuse_recent avec webhook_url. Ce code signale aussi un corps JSON invalide. |
| 422 | invalid_url | Non | Le lien doit venir de YouTube, X, TikTok, Instagram, Facebook, Bluesky ou d'une autre plateforme de la liste Sources et options. Si vous indiquez platform, sa valeur doit correspondre au lien. |
| 422 | unsupported_platform | Non | La valeur de platform ne correspond à aucune plateforme acceptée. |
| 422 | unsupported_media | Non | L'extension du fichier importé n'est pas acceptée. |
| 401 | unauthorized | Non | La clé ou le token manque, n'est pas valide, a expiré ou a été révoqué. Pour un token d'upload, il est invalide ou expiré. |
| 403 | insufficient_scope | Non | Le token OAuth n'a pas le scope transcriptions:read ou transcriptions:write nécessaire à cet appel. |
| 403 | email_not_verified | Non | Confirmez votre adresse e-mail pour pouvoir lancer une transcription. |
| 402 | insufficient_minutes | Non | Votre solde utilisable est à 0 ou ne couvre pas la durée de la transcription. |
| 402 | no_active_plan | Non | Vous essayez d'acheter une recharge sans offre payante active. Ce code vient de l'endpoint de facturation du tableau de bord, jamais des endpoints de transcription. |
| 404 | not_found | Non | Aucune transcription ne correspond, ou elle appartient à une autre équipe. |
| 409 | upload_incomplete | Non | Certains blocs ne sont pas arrivés. Envoyez les blocs manquants, puis relancez la finalisation de l'upload. |
| 409 | invalid_state | Non | Le statut de la transcription n'autorise pas l'upload. Vous ne pouvez donc ni envoyer de blocs ni finaliser l'upload. |
| 409 | idempotency_conflict | Non | Vous avez déjà utilisé cette Idempotency-Key avec d'autres paramètres. |
| 413 | media_too_large | Non | Le fichier dépasse la taille autorisée. Consultez Importer des fichiers. |
| 413 | invalid_request | Non | Le corps JSON dépasse 1 Mo. Pour un fichier trop volumineux, le code est media_too_large. |
| 429 | rate_limited | Oui | Vous avez dépassé le nombre d'appels par minute. Attendez le délai en secondes donné par Retry-After. |
| 429 | too_many_active_jobs | Oui | Trop de transcriptions tournent en parallèle ou trop d'uploads restent ouverts. Attendez le délai en secondes donné par Retry-After. |
| 500 | internal_error | Oui | Notre serveur a rencontré une erreur. Réessayez dans un instant. |
| 503 | service_unavailable | Oui | transcript1 est temporairement indisponible. Réessayez dans un instant. |
Pour les appels du navigateur authentifiés par un cookie de connexion, nous vérifions aussi l'origine. Si l'appel vient d'un autre site, vous recevez 403 forbidden_origin.
Ce contrôle ne concerne pas les appels qui utilisent un en-tête Authorization.
Toutes les réponses 429 incluent Retry-After, en secondes. Les plafonds de chaque offre figurent dans Facturation et limites.
Gérer les nouvelles tentatives
- Relancez automatiquement un appel seulement si
retryablevauttrue. C'est le cas pourrate_limited,too_many_active_jobs,internal_erroretservice_unavailable. - Si la réponse fournit
Retry-After, respectez ce délai. Sinon, augmentez progressivement l'attente entre les appels. - Gardez la même valeur d'
Idempotency-Keyquand vous renvoyezPOST /v1/transcriptions. Vous évitez ainsi de payer deux fois si le premier appel a abouti. - Avec les autres codes, corrigez d'abord la cause de l'erreur.
Quand le traitement échoue après acceptation
Si la transcription passe au statut failed, consultez son objet error : il contient code et message.
L'appel de création peut avoir réussi avant que le traitement échoue. Vérifiez donc error lors de vos appels de suivi ou à la réception du webhook transcription.failed.
error.code | Cause | Que faire ? |
|---|---|---|
media_unavailable | La vidéo est introuvable ou n'est plus accessible. | Ne relancez pas le même lien sans vérifier l'URL. |
media_private | L'accès à la vidéo est privé. | Utilisez un post public, ou une vidéo YouTube publique ou non répertoriée. Relancer le même lien ne changera rien. |
login_required | Il faut se connecter à la plateforme pour accéder à la vidéo. | Ne réessayez pas : cet échec est définitif et ne déclenche aucune nouvelle tentative. |
no_audio | Aucune piste audio n'est présente dans la vidéo. | Ne réessayez pas : cet échec est définitif et ne déclenche aucune nouvelle tentative. |
age_restricted | La plateforme limite la vidéo selon l'âge. | Ne relancez pas le lien ; importez plutôt le fichier. |
live_stream | Le direct est encore en cours ou n'a pas commencé. | Attendez la fin du direct avant de réessayer. |
no_captions | Vous avez choisi source avec la valeur captions, mais aucune piste de sous-titres n'est exploitable. | Choisissez source: "auto" ou "stt". |
media_too_long | L'enregistrement dépasse les 5 heures acceptées pour le speech-to-text. | Découpez-le avant de l'envoyer de nouveau. |
unsupported_media | Le fichier est illisible ou ne contient pas de piste audio. | Envoyez un fichier dans un format accepté plutôt que de relancer le même. |
no_speech | Aucune parole détectée. | Inutile de relancer ce traitement. |
unsupported_language | Nous ne prenons pas en charge la langue de l'enregistrement. | Corrigez language avec un code accepté ou "auto" avant de réessayer. |
insufficient_minutes | Le solde ne suffisait plus au moment de facturer la transcription. | Achetez une recharge, puis réessayez. |
fetch_failed | Le téléchargement a échoué malgré plusieurs tentatives. | Réessayez plus tard. |
transcription_failed | Le speech-to-text a échoué malgré plusieurs tentatives. | Réessayez plus tard. |
Si le traitement échoue ou si vous l'annulez, vous ne payez rien. Nous recréditons les minutes déjà prélevées.
Objet Transcription
{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "completed",
"source": {
"platform": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"media_id": "dQw4w9WgXcQ"
},
"media": {
"title": "Example video",
"author": "Example channel",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"duration_seconds": 212
},
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": "youtube_captions",
"caption_kind": "auto_generated",
"language": "en",
"billed_minutes": 4,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": "2026-10-13T09:30:04.000Z",
"deleted_at": null,
"transcript": {
"text": "Welcome back to the channel. Today we are looking at how transcripts are made.",
"speakers": [],
"segments": [
{
"start": 0,
"end": 4.2,
"speaker": null,
"language": "en",
"text": "Welcome back to the channel."
},
{
"start": 4.2,
"end": 9.8,
"speaker": null,
"language": "en",
"text": "Today we are looking at how transcripts are made."
}
]
}
}Champs
- idstringobligatoire
- objectstringobligatoire
Valeurs possibles
transcription - statusstringobligatoire
Valeurs possibles
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
With
url- platformstringobligatoire
- urlstringobligatoireaccepte null
- media_idstringobligatoireaccepte null
With
filename- platformstringobligatoire
Valeurs possibles
upload - filenamestringobligatoireaccepte null
- sizenumberobligatoireaccepte null
- mediaobjectobligatoireaccepte null
Afficher les sous-champsMasquer les sous-champs
- titlestringfacultatifaccepte null
- authorstringfacultatifaccepte null
- author_urlstringfacultatifaccepte null
- thumbnail_urlstringfacultatifaccepte null
- filenamestringfacultatif
- mime_typestringfacultatif
- sizenumberfacultatif
- duration_secondsnumberfacultatifaccepte null
- optionsobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
- sourcestringobligatoire
Valeurs possibles
autocaptionsstt - languagestringobligatoire
- diarizebooleanobligatoire
- transcript_sourcestringobligatoireaccepte null
Valeurs possibles
youtube_captionsx_captionsspeech_to_text - caption_kindstringobligatoireaccepte null
Valeurs possibles
manualauto_generated - languagestringobligatoireaccepte null
- billed_minutesintegerobligatoireaccepte null
- cachedbooleanobligatoire
- errorobjectobligatoireaccepte null
Afficher les sous-champsMasquer les sous-champs
- codestringobligatoire
- messagestringobligatoireaccepte null
- created_atstring · date-timeobligatoireaccepte null
- completed_atstring · date-timeobligatoireaccepte null
- deleted_atstring · date-timeobligatoireaccepte null
When the transcription was deleted. Always
nullunless the request includesinclude_deleted=true. - transcriptobjectfacultatif
Included in
GETresponses for completed transcriptions.Afficher les sous-champsMasquer les sous-champs
- textstringobligatoire
- speakersarray of stringsobligatoire
- segmentsarray of objectsobligatoire
Afficher les sous-champsMasquer les sous-champs
- startnumberobligatoire
- endnumberobligatoire
- speakerstringobligatoireaccepte null
- languagestringobligatoireaccepte null
- textstringobligatoire
- wordsarray of objectsfacultatifaccepte null
Afficher les sous-champsMasquer les sous-champs
- startnumberobligatoire
- endnumberobligatoire
- textstringobligatoire
- confidencenumberfacultatifaccepte null
- speakerstringobligatoireaccepte null
Transcriptions
Create, read, list and delete transcriptions of video links and uploaded files.
Create a transcription
POST /v1/transcriptionsTranscribes an uploaded file or a YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat link. Social posts must be public; only the first video is used.
Twitch accepts clips and completed VODs; Pinterest accepts native video pins; LinkedIn accepts public video posts; Snapchat accepts Spotlight. New platforms require public recorded native media without supplied account cookies; no live streams or external embeds.
platform is optional and detected from the link. Captions are YouTube/X-only. All sources use the same per-minute price.
Returns 200 for a final result, 201 when awaiting an upload and 202 while processing. Pass wait to wait up to 60 seconds for a final status.
Pass reuse_recent=true with a platform URL to reuse a transcription of the same video and options from the last 24 hours. The response includes reused: true, with no additional charge. Short links may not be matched. An Idempotency-Key replay takes precedence.
curl -X POST https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "queued",
"source": {
"platform": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"media_id": "dQw4w9WgXcQ"
},
"media": null,
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": null,
"caption_kind": null,
"language": null,
"billed_minutes": null,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": null,
"deleted_at": null,
"reused": false
}Paramètres de requête
- waitintegerfacultatifaccepte nullPar défaut : 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- reuse_recentstringfacultatifPar défaut : false
For platform URLs only. Cannot be combined with
webhook_url. Returns the team's most recent transcription of the same video with the samesource,languageanddiarize. It must have been created in the last 24 hours and must not befailedorcanceled. Reuses that transcription without creating or charging for a new one.Valeurs possibles
truefalse
En-têtes HTTP
- Idempotency-Keystringfacultatif
Returns the original transcription when you repeat a request with the same key and parameters.
Corps de la requête
With url
- platformstringfacultatif
Optional; detected from the link. If supplied, must match the link.
Valeurs possibles
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - urlstringobligatoire
YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat video link. Social posts must be public; only the first video is used. New platforms support public recorded native video without supplied account cookies, not live streams or external embeds.
- sourcestringfacultatif
"auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.
Valeurs possibles
autocaptionsstt - languagestringfacultatif
- diarizebooleanfacultatif
- webhook_urlstring · urifacultatif
With upload
- uploadobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
- filenamestringobligatoire
- sizeintegerobligatoire
- mime_typestringfacultatif
- sourcestringfacultatif
Valeurs possibles
autostt - languagestringfacultatif
- diarizebooleanfacultatif
- webhook_urlstring · urifacultatif
multipart/form-data
- filestring · binaryobligatoire
- sourcestringfacultatif
Valeurs possibles
autostt - languagestringfacultatif
- diarizebooleanfacultatif
- webhook_urlstring · urifacultatif
Réponses
200 OK— The transcription reached a final status201 Created— The transcription is awaiting a chunked upload.uploaddescribes where to send each chunk.202 Accepted— The transcription is processing
Réponses d’erreur
400 Bad Request— The JSON request body is malformed401 Unauthorized— Missing or invalid credential402 Payment Required— Not enough minutes. Applies to every request body format.403 Forbidden— Insufficient scope, unverified email, cross-site request or a single-member team plan409 Conflict—Idempotency-Keywas reused with different parameters.413 Content Too Large— The upload or the JSON request body is too large422 Unprocessable Content— Invalid request, URL, platform or file type429 Too Many Requests— Too many requests or too many active transcriptions. Wait for the number of seconds inRetry-After.
Get a transcription
GET /v1/transcriptions/{id}Returns the transcription object. Completed transcriptions include the transcript. Use format to render it as text, SRT or WebVTT.
If you request a rendered format before completion, the response is JSON. It returns 202 while processing or 200 if the transcription failed or was canceled.
With include_deleted=true, a deleted transcription is returned as a record without a transcript. For deleted records, wait is ignored and rendered formats return 404.
curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "completed",
"source": {
"platform": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"media_id": "dQw4w9WgXcQ"
},
"media": {
"title": "Example video",
"author": "Example channel",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"duration_seconds": 212
},
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": "youtube_captions",
"caption_kind": "auto_generated",
"language": "en",
"billed_minutes": 4,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": "2026-10-13T09:30:04.000Z",
"deleted_at": null,
"transcript": {
"text": "Welcome back to the channel. Today we are looking at how transcripts are made.",
"speakers": [],
"segments": [
{
"start": 0,
"end": 4.2,
"speaker": null,
"language": "en",
"text": "Welcome back to the channel."
},
{
"start": 4.2,
"end": 9.8,
"speaker": null,
"language": "en",
"text": "Today we are looking at how transcripts are made."
}
]
}
}Paramètres de route
- idstringobligatoire
Paramètres de requête
- waitintegerfacultatifaccepte nullPar défaut : 0
Seconds to wait for a final status before responding, up to 60. Defaults to 0.
- formatstringfacultatifPar défaut : json
Valeurs possibles
jsontextsrtvtt - includestringfacultatif
Valeurs possibles
words - timestampsstringfacultatifPar défaut : false
Valeurs possibles
truefalse - include_deletedstringfacultatifPar défaut : false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valeurs possibles
truefalse
Réponses
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Réponses d’erreur
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription not found422 Unprocessable Content— Invalid query parameters429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
List transcriptions
GET /v1/transcriptionsLists your team's transcriptions, newest first, without transcripts. Pass next_cursor as cursor to get the next page.
Deleted transcriptions are hidden unless you pass include_deleted=true.
curl https://api.transcript1.com/v1/transcriptions \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"object": "list",
"data": [
{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "completed",
"source": {
"platform": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"media_id": "dQw4w9WgXcQ"
},
"media": {
"title": "Example video",
"author": "Example channel",
"author_url": "https://www.youtube.com/@examplechannel",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
"duration_seconds": 212
},
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": "youtube_captions",
"caption_kind": "auto_generated",
"language": "en",
"billed_minutes": 4,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": "2026-10-13T09:30:04.000Z",
"deleted_at": null
}
],
"next_cursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTEwLTEzVDA5OjMwOjAwLjAwMFoiLCJpZCI6IjViMGU2YzFjLTBkNmYtNGMxZi05YjVlLThmM2Y0ZDBhN2ExMSJ9"
}Paramètres de requête
- limitintegerfacultatifPar défaut : 20
- cursorstringfacultatif
- statusstringfacultatif
Valeurs possibles
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringfacultatif
- include_deletedstringfacultatifPar défaut : false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valeurs possibles
truefalse
Réponses
200 OK— A page of transcriptions
Réponses d’erreur
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan422 Unprocessable Content— Invalid query parameters or cursor429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Cancel or delete a transcription
DELETE /v1/transcriptions/{id}Cancels an active transcription or one awaiting an upload. Any charged minutes are refunded.
Deletes a completed, failed or canceled transcription together with its stored transcript.
curl -X DELETE https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"Réponse sans contenu
Paramètres de route
- idstringobligatoire
Réponses
204 No Content— Canceled or deleted
Réponses d’erreur
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope, cross-site request or a single-member team plan404 Not Found— Transcription not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Uploads
Send a large file in chunks. Start with Create a transcription using an upload body. Send each chunk, then complete the upload.
Upload one chunk
PUT /v1/transcriptions/{id}/upload/chunks/{index}Sends one chunk of a chunked upload as application/octet-stream.
Authenticate with the X-Upload-Token from the create response. This endpoint does not use a bearer credential.
The body must match the planned chunk size exactly. Sending a chunk again replaces it.
curl -X PUT https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/chunks/0 \
-H "X-Upload-Token: t1u_Zk3vYb8Nw1ZrT5xLpD0aHcE7sUj9GfMiO2yXtVnR4Bw" \
-H "Content-Type: application/octet-stream" \
--data-binary @chunk-0.bin{
"object": "upload_chunk",
"index": 0,
"size": 838860
}Paramètres de route
- idstringobligatoire
- indexintegerfacultatifaccepte null
Zero-based chunk number from the upload plan
En-têtes HTTP
- X-Upload-Tokenstringobligatoire
Corps de la requête
- (contenu brut)string · binaryobligatoire
Réponses
200 OK— The chunk was stored
Réponses d’erreur
401 Unauthorized— Missing, invalid or expired upload token404 Not Found— Transcription not found409 Conflict— The transcription is no longer awaiting an upload422 Unprocessable Content— Index outside the chunk plan or wrong body size
Get upload progress
GET /v1/transcriptions/{id}/uploadLists the received chunks of a chunked upload so an interrupted upload can resume.
curl https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"object": "upload",
"status": "awaiting_upload",
"total_bytes": 48210334,
"uploaded_bytes": 4194300,
"received_chunks": [
0,
1,
2,
3,
4
],
"chunks": [
{
"index": 0,
"offset": 0,
"size": 838860
},
{
"index": 1,
"offset": 838860,
"size": 838860
},
{
"index": 2,
"offset": 1677720,
"size": 838860
},
{
"index": 3,
"offset": 2516580,
"size": 838860
},
{
"index": 4,
"offset": 3355440,
"size": 838860
},
{
"index": 5,
"offset": 4194300,
"size": 8388608
},
{
"index": 6,
"offset": 12582908,
"size": 8388608
},
{
"index": 7,
"offset": 20971516,
"size": 8388608
},
{
"index": 8,
"offset": 29360124,
"size": 8388608
},
{
"index": 9,
"offset": 37748732,
"size": 8388608
},
{
"index": 10,
"offset": 46137340,
"size": 2072994
}
],
"expires_at": "2026-10-13T10:30:00.000Z"
}Paramètres de route
- idstringobligatoire
Réponses
200 OK— Upload progress
Réponses d’erreur
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— Transcription or upload not found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Complete a chunked upload
POST /v1/transcriptions/{id}/upload/completeChecks that every planned chunk arrived with the planned size. Then assembles the file and queues the transcription.
curl -X POST https://api.transcript1.com/v1/transcriptions/tr_4fHq8ZbN2xLm0PqRsTuVwX/upload/complete \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"id": "tr_4fHq8ZbN2xLm0PqRsTuVwX",
"object": "transcription",
"status": "queued",
"source": {
"platform": "upload",
"filename": "interview.m4a",
"size": 48210334
},
"media": {
"filename": "interview.m4a",
"mime_type": "audio/mp4",
"size": 48210334
},
"options": {
"source": "auto",
"language": "auto",
"diarize": false
},
"transcript_source": null,
"caption_kind": null,
"language": null,
"billed_minutes": null,
"cached": false,
"error": null,
"created_at": "2026-10-13T09:30:00.000Z",
"completed_at": null,
"deleted_at": null
}Paramètres de route
- idstringobligatoire
Réponses
202 Accepted— The transcription is queued
Réponses d’erreur
401 Unauthorized— Missing or invalid credential402 Payment Required— Not enough minutes to queue the transcription. The upload stays awaiting completion.403 Forbidden— Insufficient scope, cross-site request or a single-member team plan404 Not Found— Transcription or upload not found409 Conflict—upload_incompletemeans chunks are missing.missing_chunkslists them.invalid_statemeans the transcription is not awaiting an upload.429 Too Many Requests— Too many requests or too many active transcriptions. Wait for the number of seconds inRetry-After.
Account
Your plan, remaining minutes and rate limits.
Get your account
GET /v1/accountReturns the authenticated user, current plan and remaining transcription minutes.
curl https://api.transcript1.com/v1/account \
-H "Authorization: Bearer $TRANSCRIPT1_API_KEY"{
"object": "account",
"user": {
"id": "5b0e6c1c-0d6f-4c1f-9b5e-8f3f4d0a7a11",
"email": "[email protected]"
},
"plan": {
"id": "9d4e0c0a-2b8a-4f0c-8d63-6a8d3c8a1f22",
"name": "Monthly"
},
"minutes": {
"remaining": 1180,
"cycle": 980,
"topup": 200,
"topup_usable": true,
"resets_at": "2026-11-13T09:30:00.000Z"
},
"renews_at": "2026-11-13T09:30:00.000Z",
"limits": {
"requests_per_minute": 200,
"max_active_jobs": 10
}
}Réponses
200 OK— The authenticated user's account
Réponses d’erreur
401 Unauthorized— Missing or invalid credential403 Forbidden— Insufficient scope or a single-member team plan404 Not Found— No account found429 Too Many Requests— Too many requests. Wait for the number of seconds inRetry-After.
Objet Account
{
"object": "account",
"user": {
"id": "5b0e6c1c-0d6f-4c1f-9b5e-8f3f4d0a7a11",
"email": "[email protected]"
},
"plan": {
"id": "9d4e0c0a-2b8a-4f0c-8d63-6a8d3c8a1f22",
"name": "Monthly"
},
"minutes": {
"remaining": 1180,
"cycle": 980,
"topup": 200,
"topup_usable": true,
"resets_at": "2026-11-13T09:30:00.000Z"
},
"renews_at": "2026-11-13T09:30:00.000Z",
"limits": {
"requests_per_minute": 200,
"max_active_jobs": 10
}
}Champs
- objectstringobligatoire
Valeurs possibles
account - userobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
- idstringobligatoire
- emailstringobligatoire
- planobjectobligatoireaccepte null
Afficher les sous-champsMasquer les sous-champs
- idstringobligatoire
- namestringobligatoire
- minutesobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
- remainingnumberobligatoire
- cyclenumberobligatoire
- topupnumberobligatoire
- topup_usablebooleanobligatoire
- resets_atstring · date-timeobligatoireaccepte null
- renews_atstring · date-timeobligatoireaccepte null
- limitsobjectobligatoire
Afficher les sous-champsMasquer les sous-champs
- requests_per_minutenumberobligatoire
- max_active_jobsnumberobligatoire
Webhooks
import { Buffer } from 'node:buffer';
import crypto from 'node:crypto';
// header: X-Transcript1-Signature, rawBody: the request body exactly as received,
// secret: your full signing secret including the whsec_ prefix.
export const verifySignature = (secret, header, rawBody, nowSeconds = Math.floor(Date.now() / 1000)) => {
const fields = Object.fromEntries(header.split(',').map(part => part.trim().split('=')));
const t = Number(fields.t);
if (!Number.isInteger(t) || !fields.v1 || Math.abs(nowSeconds - t) > 300) {
return false;
}
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return fields.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(fields.v1), Buffer.from(expected));
};{
"type": "transcription.completed",
"created_at": "2026-10-13T09:30:04.000Z",
"data": {
"id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
"object": "transcription",
"status": "completed",
"transcript_source": "youtube_captions",
"billed_minutes": 4,
"error": null
}
}Pour recevoir une notification en fin de traitement, fournissez webhook_url à la création de la transcription. Nous envoyons un POST signé à cette adresse si le traitement aboutit ou échoue.
Cette option est réservée à l'API REST : le serveur MCP ne propose pas de paramètre webhook.
Choisir l'adresse de réception
Sur POST /v1/transcriptions, placez webhook_url à l'endroit adapté à votre source :
- Dans le corps JSON pour un lien vidéo compatible ou pour réserver un upload en blocs.
- Dans un champ de formulaire pour un fichier envoyé en une seule requête.
Votre URL doit respecter ces conditions :
- utiliser HTTPS ;
- ne contenir ni nom d'utilisateur ni mot de passe ;
- se résoudre vers une adresse IP publique.
Une adresse privée, loopback, link-local ou toute autre adresse non publique provoque 422 invalid_request. Nous contrôlons l'adresse à la création de la transcription, puis avant chaque envoi.
N'utilisez pas webhook_url avec reuse_recent=true : ces options sont incompatibles.
Événements
type | Déclenchement |
|---|---|
transcription.completed | Le statut passe à completed. |
transcription.failed | Le statut passe à failed. Lisez le code et le message dans data.error. |
Si vous annulez la transcription, nous n'envoyons pas de webhook.
Lire la notification
Vous recevez un corps JSON :
created_atindique quand nous avons créé l'événement.datacontient l'objet de transcription, sans le champtranscript.
Le texte se récupère séparément : prenez l'id dans data, puis appelez GET /v1/transcriptions/:id.
L'appel comporte aussi les en-têtes suivants :
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-Transcript1-Signature, à vérifier comme indiqué ci-dessous.
Vérifier la signature
Pour chaque envoi, vous recevez X-Transcript1-Signature sous la forme t=<unix seconds>,v1=<hex digest>.
tdonne le timestamp Unix de la signature, en secondes.- Pour calculer
v1, appliquez HMAC-SHA256 à"<t>.<raw body>", puis encodez le condensat en hexadécimal. Assemblez la valeur det, un point et le corps reçu sans aucune modification. La clé HMAC est votre secret de signature complet, y compris son préfixewhsec_.
Vérifiez la signature sur les octets du corps brut, avant de parser le JSON. Parser puis sérialiser de nouveau peut changer les espaces ou l'ordre des clés : la signature ne correspondrait plus.
- Utilisez une comparaison en temps constant pour les signatures.
- Refusez l'appel si
test trop éloigné de l'heure actuelle. Nos exemples acceptent un écart de 5 minutes. - Avec Express, récupérez le corps en texte brut avant tout parsing.
- Avec Flask, fournissez
request.get_data(as_text=True)au paramètreraw_body.
Gérer le secret de signature
Votre équipe possède un secret préfixé par whsec_. Nous l'utilisons pour signer les webhooks de toutes ses transcriptions.
Vous pouvez afficher ce secret ou le renouveler depuis « Webhooks ».
Le remplacement prend effet immédiatement. Dès lors, chaque webhook est signé avec le nouveau secret.
Réception et nouvelles tentatives
- Répondez avec un statut
2xxpour confirmer la réception. - Nous considérons l'envoi comme un échec pour tout autre statut, en cas d'erreur de connexion ou sans réponse sous 10 secondes.
- Après un échec, nous réessayons jusqu'à atteindre 6 tentatives au total. Les délais augmentent de façon exponentielle : 2, 4, 8, 16 puis 32 minutes. La dernière tentative intervient environ une heure après la première.
- Fournissez l'URL finale : transcript1 ne suit pas les redirections. Un statut
3xxcompte donc comme un échec d'envoi. - Prévoyez de recevoir plusieurs fois la même notification, notamment si votre serveur répond après le délai maximal. Dédupliquez-la à partir de
data.idet detype.