DocumentaçãoReferência da API REST

Referência da API REST

Consulte cada endpoint de /v1, com parâmetros e exemplos, ou baixe a especificação OpenAPI em JSON ou YAML.

Introdução

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

Use https://api.transcript1.com/v1 como URL base da API.

  • Envie e receba corpos JSON. Os nomes dos campos usam snake_case.
  • Datas e horários vêm em UTC no formato ISO 8601, como 2026-10-13T09:30:00.000Z.
  • Durações e marcações de tempo da transcrição usam segundos.
  • As respostas de erro seguem um formato único. Consulte Erros.
  • Nas respostas a chamadas autenticadas, confira X-RateLimit-Limit e X-RateLimit-Remaining para acompanhar sua cota de requisições. Os limites estão em Planos, minutos e limites.
  • Com source=auto, buscamos primeiro legendas no idioma original do YouTube, X, TikTok, Bluesky, Dailymotion e LinkedIn. Se não pudermos usá-las, transcrevemos o áudio com speech-to-text. Nem todo vídeo tem legendas. O modo source=captions (somente legendas) não baixa áudio nem recorre ao STT: se não houver uma faixa que possa ser usada, retorna no_captions. Com source=stt ou identificação de falantes, vamos direto ao áudio. Em Links aceitos e opções, você encontra as restrições de cada plataforma e quais trazem marcações de tempo por segmento ou por palavra.

A especificação OpenAPI está disponível para download nestes formatos:

Autenticação

curl https://api.transcript1.com/v1/account \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"

Para autenticar a chamada, use o cabeçalho Authorization no formato Authorization: Bearer <token>.

  • Chave de API: começa com t1_ e permite chamar qualquer endpoint. Crie a sua em “API keys”.
  • Token de acesso OAuth: começa com t1o_. Clientes MCP, como Claude e ChatGPT, recebem esse token ao conectar sua conta. Ele usa os escopos transcriptions:read e transcriptions:write.
EscopoChamadas permitidas
transcriptions:readGET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload e GET /v1/account
transcriptions:writePOST /v1/transcriptions, DELETE /v1/transcriptions/:id e POST /v1/transcriptions/:id/upload/complete
  • Se faltar o escopo exigido pela chamada, a API responde 403 insufficient_scope.
  • Se você não enviar uma credencial válida, a resposta será 401 unauthorized.

O envio de partes do arquivo usa outro token: o X-Upload-Token, que você recebe ao criar o upload. Passe esse cabeçalho em PUT /v1/transcriptions/:id/upload/chunks/:index. Veja o passo a passo em Uploads.

Idempotência

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"}'

Use Idempotency-Key para poder repetir uma chamada a POST /v1/transcriptions sem criar outra transcrição por engano.

Escolha um valor de 1 a 255 caracteres e envie no cabeçalho da requisição. Esse campo não vai na query string.

  • Se a chave e os parâmetros forem os mesmos, a API devolve a transcrição original e não cobra de novo.
  • Se você mantiver a chave, mas mudar os parâmetros, receberá 409 idempotency_conflict.
  • Ao repetir a criação de um upload em partes com a mesma chave, você recebe um token de upload novo.

Erros

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
  }
}
  • Quando a API recusa a chamada, você recebe um erro de requisição.
  • Quando ela aceita a transcrição, mas o processamento falha depois, o objeto da transcrição fica com status igual a failed.

Como ler a resposta de erro

Se uma chamada a /v1 falhar, procure o objeto error na resposta. Ele traz code, message e retryable.

  • Use code para decidir o que fazer na sua aplicação.
  • Exiba message como explicação para o usuário. O texto pode mudar.
  • Se retryable for true, vale repetir a mesma chamada mais tarde.

Dependendo do erro, outros campos aparecem junto de retryable:

CampoCódigo associadoO que informa
action_urlinsufficient_minutesLink para contratar um plano ou comprar uma recarga.
minutes_needed, minutes_remaininginsufficient_minutesQuantos minutos a chamada precisa consumir e quantos você tem. Se a duração ainda não for conhecida, o primeiro valor será null.
supported_platformsunsupported_platformValores de plataforma aceitos: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"].
missing_chunksupload_incompleteÍndices das partes que ainda faltam no upload.
max_bytesmedia_too_largeTamanho máximo de arquivo permitido na sua conta, em bytes.
paramsinvalid_requestObjeto com os campos inválidos do corpo ou da query string e a explicação do problema em cada um.

Quando a API recusa a chamada

Status HTTPcodePode repetir?O que aconteceu
400, 422invalid_requestNãoFalta um parâmetro ou há um campo inválido no corpo. Isso inclui combinar diarize com source: "captions", combinar reuse_recent com webhook_url ou enviar um JSON inválido.
422invalid_urlNãoO link não foi aceito ou platform não corresponde ao endereço. Use YouTube, X, TikTok, Instagram, Facebook, Bluesky ou outra plataforma de Links aceitos e opções.
422unsupported_platformNãoO valor de platform não está entre as plataformas aceitas.
422unsupported_mediaNãoA extensão do arquivo enviado não está entre as aceitas.
401unauthorizedNãoFalta a credencial, ou ela é inválida, expirou ou foi revogada. Também vale para token de upload inválido ou expirado.
403insufficient_scopeNãoO token OAuth não tem o escopo necessário: transcriptions:read ou transcriptions:write.
403email_not_verifiedNãoVocê precisa confirmar o e-mail antes de criar uma transcrição.
402insufficient_minutesNãoO saldo disponível é 0 ou não cobre a duração da transcrição.
402no_active_planNãoA compra de recarga exige um plano pago ativo. Esse erro vem do endpoint de cobrança do painel, não dos endpoints de transcrição.
404not_foundNãoEssa transcrição não existe ou é de outra equipe.
409upload_incompleteNãoAinda faltam partes do arquivo. Envie o que falta e peça a conclusão do upload novamente.
409invalid_stateNãoA transcrição já saiu da etapa de espera pelo upload. Não é mais possível enviar partes ou concluir o envio.
409idempotency_conflictNãoVocê já usou esse Idempotency-Key com outros parâmetros.
413media_too_largeNãoO tamanho do arquivo ultrapassa o seu limite. Confira Uploads.
413invalid_requestNãoO corpo JSON ultrapassa 1 MB. Para arquivos grandes, o código é media_too_large.
429rate_limitedSimVocê atingiu o limite de chamadas por minuto. Aguarde o número de segundos de Retry-After.
429too_many_active_jobsSimVocê atingiu o limite de transcrições em andamento ou de uploads abertos. Aguarde o número de segundos de Retry-After.
500internal_errorSimTivemos um erro interno. Aguarde um pouco e tente novamente.
503service_unavailableSimO transcript1 está indisponível no momento. Aguarde um pouco e tente novamente.

Quando o navegador autentica a chamada pelo cookie de login, também conferimos a origem. Se a chamada vier de outro site, a resposta será 403 forbidden_origin.

Essa verificação não afeta chamadas à API com o cabeçalho Authorization.

Toda resposta 429 informa em Retry-After quantos segundos você deve esperar. Consulte os valores de cada plano em Planos, minutos e limites.

Quando e como tentar novamente

  • Repita a chamada apenas se retryable for true. Isso vale para rate_limited, too_many_active_jobs, internal_error e service_unavailable.
  • Respeite a espera de Retry-After quando ele vier na resposta. Sem esse cabeçalho, aumente o intervalo a cada tentativa.
  • Para repetir POST /v1/transcriptions, mantenha o mesmo Idempotency-Key. Assim você evita outra cobrança caso a primeira chamada tenha funcionado.
  • Nos demais erros, corrija a causa antes de enviar a chamada novamente.

Falhas durante a transcrição

Se o processamento falhar, o objeto da transcrição fica com status igual a failed. O objeto error traz code e message para explicar o problema.

Isso pode acontecer depois da resposta à chamada de criação. Leia error nas consultas de status ou ao receber o webhook transcription.failed.

error.codeO que aconteceuVale tentar novamente?
media_unavailableO vídeo não existe ou saiu do ar.Não. Confira o link.
media_privateO vídeo é privado.Não. Envie um post público ou um vídeo do YouTube público ou não listado.
login_requiredA plataforma só libera o conteúdo após login.Não. O serviço não repete essa tentativa.
no_audioNão há faixa de áudio no vídeo.Não. O serviço não repete essa tentativa.
age_restrictedO acesso ao vídeo tem restrição de idade.Não pelo link. Envie o arquivo por upload.
live_streamA transmissão está ao vivo ou ainda não começou.Espere a transmissão terminar.
no_captionsVocê escolheu captions em source, mas não há uma faixa de legendas que possa ser usada.Troque para source: "auto" ou "stt".
media_too_longA gravação ultrapassa o limite de 5 horas do speech-to-text.Divida a gravação antes de enviar.
unsupported_mediaNão foi possível ler o arquivo, ou ele não tem faixa de áudio.Envie outro arquivo em um formato aceito.
no_speechNenhuma fala detectada.Não.
unsupported_languageO serviço não aceita o idioma da gravação.Corrija language para um código aceito ou "auto".
insufficient_minutesO saldo acabou antes de cobrarmos a transcrição.Faça uma recarga antes de tentar.
fetch_failedNão conseguimos baixar o áudio ou vídeo, mesmo após várias tentativas.Sim. Tente mais tarde.
transcription_failedA transcrição por speech-to-text falhou após várias tentativas.Sim. Tente mais tarde.

Se a transcrição falhar ou você cancelar, não paga por ela. Se já tivermos descontado os minutos, eles voltam para o seu saldo.

Objeto Transcription

Objeto 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."
      }
    ]
  }
}

Atributos

  • idstringobrigatório
  • objectstringobrigatório

    Valores permitidostranscription

  • statusstringobrigatório

    Valores permitidosawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • sourceobjectobrigatório
    Expandir atributos
    With url
    • platformstringobrigatório
    • urlstringobrigatórioaceita null
    • media_idstringobrigatórioaceita null
    With filename
    • platformstringobrigatório

      Valores permitidosupload

    • filenamestringobrigatórioaceita null
    • sizenumberobrigatórioaceita null
  • mediaobjectobrigatórioaceita null
    Expandir atributos
    • titlestringopcionalaceita null
    • authorstringopcionalaceita null
    • author_urlstringopcionalaceita null
    • thumbnail_urlstringopcionalaceita null
    • filenamestringopcional
    • mime_typestringopcional
    • sizenumberopcional
    • duration_secondsnumberopcionalaceita null
  • optionsobjectobrigatório
    Expandir atributos
    • sourcestringobrigatório

      Valores permitidosautocaptionsstt

    • languagestringobrigatório
    • diarizebooleanobrigatório
  • transcript_sourcestringobrigatórioaceita null

    Valores permitidosyoutube_captionsx_captionsspeech_to_text

  • caption_kindstringobrigatórioaceita null

    Valores permitidosmanualauto_generated

  • languagestringobrigatórioaceita null
  • billed_minutesintegerobrigatórioaceita null
  • cachedbooleanobrigatório
  • errorobjectobrigatórioaceita null
    Expandir atributos
    • codestringobrigatório
    • messagestringobrigatórioaceita null
  • created_atstring · date-timeobrigatórioaceita null
  • completed_atstring · date-timeobrigatórioaceita null
  • deleted_atstring · date-timeobrigatórioaceita null

    When the transcription was deleted. Always null unless the request includes include_deleted=true.

  • transcriptobjectopcional

    Included in GET responses for completed transcriptions.

    Expandir atributos
    • textstringobrigatório
    • speakersarray of stringsobrigatório
    • segmentsarray of objectsobrigatório
      Expandir atributos
      • startnumberobrigatório
      • endnumberobrigatório
      • speakerstringobrigatórioaceita null
      • languagestringobrigatórioaceita null
      • textstringobrigatório
      • wordsarray of objectsopcionalaceita null
        Expandir atributos
        • startnumberobrigatório
        • endnumberobrigatório
        • textstringobrigatório
        • confidencenumberopcionalaceita null
        • speakerstringobrigatórioaceita 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
}

Query

  • waitintegeropcionalaceita nullValor padrão: 0

    Seconds to wait for a final status before responding, up to 60. Defaults to 0.

  • reuse_recentstringopcionalValor padrão: 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.

    Valores permitidostruefalse

Headers

  • Idempotency-Keystringopcional

    Returns the original transcription when you repeat a request with the same key and parameters.

Body

With url
  • platformstringopcional

    Optional; detected from the link. If supplied, must match the link.

    Valores permitidosyoutubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat

  • urlstringobrigatório

    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.

  • sourcestringopcional

    "auto" uses YouTube or X captions when available, otherwise speech-to-text. "captions" is YouTube/X-only. "stt" always uses speech-to-text.

    Valores permitidosautocaptionsstt

  • languagestringopcional
  • diarizebooleanopcional
  • webhook_urlstring · uriopcional
With upload
  • uploadobjectobrigatório
    Expandir atributos
    • filenamestringobrigatório
    • sizeintegerobrigatório
    • mime_typestringopcional
  • sourcestringopcional

    Valores permitidosautostt

  • languagestringopcional
  • diarizebooleanopcional
  • webhook_urlstring · uriopcional
multipart/form-data
  • filestring · binaryobrigatório
  • sourcestringopcional

    Valores permitidosautostt

  • languagestringopcional
  • diarizebooleanopcional
  • webhook_urlstring · uriopcional

Retorna

  • 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

Outros códigos de status

  • 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."
      }
    ]
  }
}

Path

  • idstringobrigatório

Query

  • waitintegeropcionalaceita nullValor padrão: 0

    Seconds to wait for a final status before responding, up to 60. Defaults to 0.

  • formatstringopcionalValor padrão: json

    Valores permitidosjsontextsrtvtt

  • includestringopcional

    Valores permitidoswords

  • timestampsstringopcionalValor padrão: false

    Valores permitidostruefalse

  • include_deletedstringopcionalValor padrão: false

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

    Valores permitidostruefalse

Retorna

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

Outros códigos de status

  • 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"
}

Query

  • limitintegeropcionalValor padrão: 20
  • cursorstringopcional
  • statusstringopcional

    Valores permitidosawaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled

  • platformstringopcional
  • include_deletedstringopcionalValor padrão: false

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

    Valores permitidostruefalse

Retorna

  • 200 OK — A page of transcriptions

Outros códigos de status

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

Resposta sem corpo

Path

  • idstringobrigatório

Retorna

  • 204 No Content — Canceled or deleted

Outros códigos de status

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

Path

  • idstringobrigatório
  • indexintegeropcionalaceita null

    Zero-based chunk number from the upload plan

Headers

  • X-Upload-Tokenstringobrigatório

Body

  • (raw body)string · binaryobrigatório

Retorna

  • 200 OK — The chunk was stored

Outros códigos de status

  • 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"
}

Path

  • idstringobrigatório

Retorna

  • 200 OK — Upload progress

Outros códigos de status

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

Path

  • idstringobrigatório

Retorna

  • 202 Accepted — The transcription is queued

Outros códigos de status

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

Retorna

  • 200 OK — The authenticated user's account

Outros códigos de status

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

Objeto Account

Objeto 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
  }
}

Atributos

  • objectstringobrigatório

    Valores permitidosaccount

  • userobjectobrigatório
    Expandir atributos
    • idstringobrigatório
    • emailstringobrigatório
  • planobjectobrigatórioaceita null
    Expandir atributos
    • idstringobrigatório
    • namestringobrigatório
  • minutesobjectobrigatório
    Expandir atributos
    • remainingnumberobrigatório
    • cyclenumberobrigatório
    • topupnumberobrigatório
    • topup_usablebooleanobrigatório
    • resets_atstring · date-timeobrigatórioaceita null
  • renews_atstring · date-timeobrigatórioaceita null
  • limitsobjectobrigatório
    Expandir atributos
    • requests_per_minutenumberobrigatório
    • max_active_jobsnumberobrigatório

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
  }
}

Informe webhook_url na criação para receber um aviso quando a transcrição ficar pronta ou falhar. O transcript1 envia um POST assinado para esse endereço.

Esse recurso está disponível só na API REST. As ferramentas do servidor MCP não aceitam um parâmetro de webhook.

Configure o endereço de entrega

Na chamada a POST /v1/transcriptions, envie webhook_url assim:

  • Se estiver enviando um link aceito ou criando um upload em partes, coloque o campo no corpo JSON.
  • Se enviar o arquivo de uma vez, use um campo de formulário.

Confira os requisitos da URL:

  • Precisa usar HTTPS.
  • Não pode incluir usuário ou senha no endereço.
  • Precisa apontar para um IP público.

Se o endereço for privado, de loopback, link-local ou de qualquer outro tipo não público, você recebe 422 invalid_request. Conferimos o endereço na criação da transcrição e antes de cada entrega.

Não envie webhook_url junto com reuse_recent=true.

Eventos

typeQuando você recebe
transcription.completedO status muda para completed.
transcription.failedO status muda para failed. Confira code e message em data.error.

Se você cancelar a transcrição, não enviamos webhook.

Payload

O aviso chega em JSON, com estes campos:

  • created_at informa quando o evento foi criado.
  • data traz o objeto da transcrição, mas sem o campo transcript.

Para buscar o texto, use o id de data em GET /v1/transcriptions/:id.

Também enviamos estes cabeçalhos:

  • Content-Type: application/json
  • User-Agent: transcript1-webhooks/1.0
  • X-Transcript1-Signature, com a assinatura explicada abaixo.

Confira a assinatura antes de ler o JSON

Você encontra a assinatura de cada entrega em X-Transcript1-Signature, no formato t=<unix seconds>,v1=<hex digest>.

  • t informa quando assinamos a requisição, em segundos Unix.
  • v1 contém o HMAC-SHA256 em hexadecimal da string "<t>.<raw body>". Monte essa string com o valor de t, um ponto e o corpo exatamente como chegou. Use o segredo de assinatura inteiro como chave, com o prefixo whsec_.

Calcule a assinatura sobre os bytes originais do corpo antes de fazer o parse do JSON. Converter o JSON em objeto e depois em texto pode mudar os espaços ou a ordem das chaves. Se isso acontecer, a assinatura deixa de conferir.

  • Faça a comparação das assinaturas em tempo constante.
  • Recuse requisições com t muito distante da hora atual. A tolerância dos exemplos é de 5 minutos.
  • No Express, receba o corpo como texto, sem passar pelo parser de JSON antes da verificação.
  • No Flask, obtenha o corpo com request.get_data(as_text=True) e passe esse texto em raw_body.

Consulte ou troque o segredo de assinatura

Cada equipe tem um segredo de assinatura com o prefixo whsec_. Usamos esse mesmo segredo nos webhooks de todas as transcrições da equipe.

Você pode consultá-lo ou gerar outro na página “Webhooks”.

A troca vale imediatamente. A partir daí, todas as entregas usam o novo segredo.

Entregas e novas tentativas

  • Responda com qualquer status 2xx para confirmar o recebimento.
  • Outro status, erro de conexão ou falta de resposta em 10 segundos faz a tentativa falhar.
  • Se a entrega falhar, tentamos de novo com backoff exponencial, até 6 tentativas no total. Os intervalos são de 2, 4, 8, 16 e 32 minutos. A última tentativa ocorre cerca de uma hora após a primeira.
  • Informe a URL final. O transcript1 não segue redirecionamentos e considera respostas 3xx uma falha de entrega.
  • Seu servidor pode receber o mesmo aviso mais de uma vez, por exemplo se responder depois do timeout. Confira data.id e type para não processar duplicatas.