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

URL de base
https://api.transcript1.com/v1

Utilisez 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-Limit et X-RateLimit-Remaining indiquent 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 mode source=captions (sous-titres uniquement) ne télécharge pas l'audio et ne lance jamais le STT : sans piste exploitable, il renvoie no_captions. Pour passer directement à l'audio, choisissez source=stt ou 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 scopes transcriptions:read et transcriptions:write.
ScopeAppels autorisés
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload et GET /v1/account
transcriptions:writePOST /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

402 Payment Required
{
  "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 status failed.

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 retryable vaut true, 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 :

ChampCode concernéInformations fournies
action_urlinsufficient_minutesLien pour souscrire une offre ou acheter une recharge.
minutes_needed, minutes_remaininginsufficient_minutesMinutes nécessaires pour cet appel (null si ce nombre n'est pas encore connu) et solde disponible.
supported_platformsunsupported_platformListe des plateformes acceptées : ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteIndex des blocs à envoyer de nouveau.
max_bytesmedia_too_largeTaille maximale des fichiers pour votre compte, en octets.
paramsinvalid_requestPour 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 HTTPcodePeut réussir sans correction ?Cause et action à effectuer
400, 422invalid_requestNonIl 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.
422invalid_urlNonLe 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.
422unsupported_platformNonLa valeur de platform ne correspond à aucune plateforme acceptée.
422unsupported_mediaNonL'extension du fichier importé n'est pas acceptée.
401unauthorizedNonLa 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é.
403insufficient_scopeNonLe token OAuth n'a pas le scope transcriptions:read ou transcriptions:write nécessaire à cet appel.
403email_not_verifiedNonConfirmez votre adresse e-mail pour pouvoir lancer une transcription.
402insufficient_minutesNonVotre solde utilisable est à 0 ou ne couvre pas la durée de la transcription.
402no_active_planNonVous 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.
404not_foundNonAucune transcription ne correspond, ou elle appartient à une autre équipe.
409upload_incompleteNonCertains blocs ne sont pas arrivés. Envoyez les blocs manquants, puis relancez la finalisation de l'upload.
409invalid_stateNonLe statut de la transcription n'autorise pas l'upload. Vous ne pouvez donc ni envoyer de blocs ni finaliser l'upload.
409idempotency_conflictNonVous avez déjà utilisé cette Idempotency-Key avec d'autres paramètres.
413media_too_largeNonLe fichier dépasse la taille autorisée. Consultez Importer des fichiers.
413invalid_requestNonLe corps JSON dépasse 1 Mo. Pour un fichier trop volumineux, le code est media_too_large.
429rate_limitedOuiVous avez dépassé le nombre d'appels par minute. Attendez le délai en secondes donné par Retry-After.
429too_many_active_jobsOuiTrop de transcriptions tournent en parallèle ou trop d'uploads restent ouverts. Attendez le délai en secondes donné par Retry-After.
500internal_errorOuiNotre serveur a rencontré une erreur. Réessayez dans un instant.
503service_unavailableOuitranscript1 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 retryable vaut true. C'est le cas pour rate_limited, too_many_active_jobs, internal_error et service_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-Key quand vous renvoyez POST /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.codeCauseQue faire ?
media_unavailableLa vidéo est introuvable ou n'est plus accessible.Ne relancez pas le même lien sans vérifier l'URL.
media_privateL'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_requiredIl 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_audioAucune 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_restrictedLa plateforme limite la vidéo selon l'âge.Ne relancez pas le lien ; importez plutôt le fichier.
live_streamLe direct est encore en cours ou n'a pas commencé.Attendez la fin du direct avant de réessayer.
no_captionsVous avez choisi source avec la valeur captions, mais aucune piste de sous-titres n'est exploitable.Choisissez source: "auto" ou "stt".
media_too_longL'enregistrement dépasse les 5 heures acceptées pour le speech-to-text.Découpez-le avant de l'envoyer de nouveau.
unsupported_mediaLe 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_speechAucune parole détectée.Inutile de relancer ce traitement.
unsupported_languageNous ne prenons pas en charge la langue de l'enregistrement.Corrigez language avec un code accepté ou "auto" avant de réessayer.
insufficient_minutesLe solde ne suffisait plus au moment de facturer la transcription.Achetez une recharge, puis réessayez.
fetch_failedLe téléchargement a échoué malgré plusieurs tentatives.Réessayez plus tard.
transcription_failedLe 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

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 possiblestranscription

  • statusstringobligatoire

    Valeurs possiblesawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • sourceobjectobligatoire
    Afficher les sous-champs
    With url
    • platformstringobligatoire
    • urlstringobligatoireaccepte null
    • media_idstringobligatoireaccepte null
    With filename
    • platformstringobligatoire

      Valeurs possiblesupload

    • filenamestringobligatoireaccepte null
    • sizenumberobligatoireaccepte null
  • mediaobjectobligatoireaccepte null
    Afficher les sous-champs
    • titlestringfacultatifaccepte null
    • authorstringfacultatifaccepte null
    • author_urlstringfacultatifaccepte null
    • thumbnail_urlstringfacultatifaccepte null
    • filenamestringfacultatif
    • mime_typestringfacultatif
    • sizenumberfacultatif
    • duration_secondsnumberfacultatifaccepte null
  • optionsobjectobligatoire
    Afficher les sous-champs
    • sourcestringobligatoire

      Valeurs possiblesautocaptionsstt

    • languagestringobligatoire
    • diarizebooleanobligatoire
  • transcript_sourcestringobligatoireaccepte null

    Valeurs possiblesyoutube_captionsx_captionsspeech_to_text

  • caption_kindstringobligatoireaccepte null

    Valeurs possiblesmanualauto_generated

  • languagestringobligatoireaccepte null
  • billed_minutesintegerobligatoireaccepte null
  • cachedbooleanobligatoire
  • errorobjectobligatoireaccepte null
    Afficher 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 null unless the request includes include_deleted=true.

  • transcriptobjectfacultatif

    Included in GET responses for completed transcriptions.

    Afficher les sous-champs
    • textstringobligatoire
    • speakersarray of stringsobligatoire
    • segmentsarray of objectsobligatoire
      Afficher les sous-champs
      • startnumberobligatoire
      • endnumberobligatoire
      • speakerstringobligatoireaccepte null
      • languagestringobligatoireaccepte null
      • textstringobligatoire
      • wordsarray of objectsfacultatifaccepte null
        Afficher 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/transcriptions

Transcribes 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 same source, language and diarize. It must have been created in the last 24 hours and must not be failed or canceled. Reuses that transcription without creating or charging for a new one.

    Valeurs possiblestruefalse

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 possiblesyoutubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat

  • 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 possiblesautocaptionsstt

  • languagestringfacultatif
  • diarizebooleanfacultatif
  • webhook_urlstring · urifacultatif
With upload
  • uploadobjectobligatoire
    Afficher les sous-champs
    • filenamestringobligatoire
    • sizeintegerobligatoire
    • mime_typestringfacultatif
  • sourcestringfacultatif

    Valeurs possiblesautostt

  • languagestringfacultatif
  • diarizebooleanfacultatif
  • webhook_urlstring · urifacultatif
multipart/form-data
  • filestring · binaryobligatoire
  • sourcestringfacultatif

    Valeurs possiblesautostt

  • languagestringfacultatif
  • diarizebooleanfacultatif
  • webhook_urlstring · urifacultatif

Réponses

  • 200 OK — The transcription reached a final status
  • 201 Created — The transcription is awaiting a chunked upload. upload describes where to send each chunk.
  • 202 Accepted — The transcription is processing

Réponses d’erreur

  • 400 Bad Request — The JSON request body is malformed
  • 401 Unauthorized — Missing or invalid credential
  • 402 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 plan
  • 409 Conflict — Idempotency-Key was reused with different parameters.
  • 413 Content Too Large — The upload or the JSON request body is too large
  • 422 Unprocessable Content — Invalid request, URL, platform or file type
  • 429 Too Many Requests — Too many requests or too many active transcriptions. Wait for the number of seconds in Retry-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 possiblesjsontextsrtvtt

  • includestringfacultatif

    Valeurs possibleswords

  • timestampsstringfacultatifPar défaut : false

    Valeurs possiblestruefalse

  • include_deletedstringfacultatifPar défaut : false

    Also returns deleted transcriptions as read-only records without a transcript. Their deleted_at is set. Defaults to false.

    Valeurs possiblestruefalse

Réponses

  • 200 OK — The transcription, or the rendered transcript
  • 202 Accepted — A rendered format was requested while the transcription is still processing

Réponses d’erreur

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription not found
  • 422 Unprocessable Content — Invalid query parameters
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

List transcriptions

GET /v1/transcriptions

Lists 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 possiblesawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringfacultatif
  • include_deletedstringfacultatifPar défaut : false

    Also returns deleted transcriptions as read-only records without a transcript. Their deleted_at is set. Defaults to false.

    Valeurs possiblestruefalse

Réponses

  • 200 OK — A page of transcriptions

Réponses d’erreur

  • 401 Unauthorized — Missing or invalid credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 422 Unprocessable Content — Invalid query parameters or cursor
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-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 credential
  • 403 Forbidden — Insufficient scope, cross-site request or a single-member team plan
  • 404 Not Found — Transcription not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-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 token
  • 404 Not Found — Transcription not found
  • 409 Conflict — The transcription is no longer awaiting an upload
  • 422 Unprocessable Content — Index outside the chunk plan or wrong body size

Get upload progress

GET /v1/transcriptions/{id}/upload

Lists 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 credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — Transcription or upload not found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Complete a chunked upload

POST /v1/transcriptions/{id}/upload/complete

Checks 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 credential
  • 402 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 plan
  • 404 Not Found — Transcription or upload not found
  • 409 Conflict — upload_incomplete means chunks are missing. missing_chunks lists them. invalid_state means 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 in Retry-After.

Account

Your plan, remaining minutes and rate limits.

Get your account

GET /v1/account

Returns 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 credential
  • 403 Forbidden — Insufficient scope or a single-member team plan
  • 404 Not Found — No account found
  • 429 Too Many Requests — Too many requests. Wait for the number of seconds in Retry-After.

Objet Account

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 possiblesaccount

  • userobjectobligatoire
    Afficher les sous-champs
    • idstringobligatoire
    • emailstringobligatoire
  • planobjectobligatoireaccepte null
    Afficher les sous-champs
    • idstringobligatoire
    • namestringobligatoire
  • minutesobjectobligatoire
    Afficher les sous-champs
    • remainingnumberobligatoire
    • cyclenumberobligatoire
    • topupnumberobligatoire
    • topup_usablebooleanobligatoire
    • resets_atstring · date-timeobligatoireaccepte null
  • renews_atstring · date-timeobligatoireaccepte null
  • limitsobjectobligatoire
    Afficher 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));
};
transcription.completed
{
  "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

typeDéclenchement
transcription.completedLe statut passe à completed.
transcription.failedLe 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_at indique quand nous avons créé l'événement.
  • data contient l'objet de transcription, sans le champ transcript.

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/json
  • User-Agent: transcript1-webhooks/1.0
  • X-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>.

  • t donne 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 de t, un point et le corps reçu sans aucune modification. La clé HMAC est votre secret de signature complet, y compris son préfixe whsec_.

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 t est 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ètre raw_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 2xx pour 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 3xx compte 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.id et de type.