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
https://api.transcript1.com/v1Use 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-LimiteX-RateLimit-Remainingpara 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 modosource=captions(somente legendas) não baixa áudio nem recorre ao STT: se não houver uma faixa que possa ser usada, retornano_captions. Comsource=sttou 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 escopostranscriptions:readetranscriptions:write.
| Escopo | Chamadas permitidas |
|---|---|
transcriptions:read | GET /v1/transcriptions, GET /v1/transcriptions/:id, GET /v1/transcriptions/:id/upload e GET /v1/account |
transcriptions:write | POST /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
{
"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
statusigual afailed.
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
codepara decidir o que fazer na sua aplicação. - Exiba
messagecomo explicação para o usuário. O texto pode mudar. - Se
retryablefortrue, vale repetir a mesma chamada mais tarde.
Dependendo do erro, outros campos aparecem junto de retryable:
| Campo | Código associado | O que informa |
|---|---|---|
action_url | insufficient_minutes | Link para contratar um plano ou comprar uma recarga. |
minutes_needed, minutes_remaining | insufficient_minutes | Quantos minutos a chamada precisa consumir e quantos você tem. Se a duração ainda não for conhecida, o primeiro valor será null. |
supported_platforms | unsupported_platform | Valores de plataforma aceitos: ["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]. |
missing_chunks | upload_incomplete | Índices das partes que ainda faltam no upload. |
max_bytes | media_too_large | Tamanho máximo de arquivo permitido na sua conta, em bytes. |
params | invalid_request | Objeto 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 HTTP | code | Pode repetir? | O que aconteceu |
|---|---|---|---|
| 400, 422 | invalid_request | Não | Falta 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. |
| 422 | invalid_url | Não | O 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. |
| 422 | unsupported_platform | Não | O valor de platform não está entre as plataformas aceitas. |
| 422 | unsupported_media | Não | A extensão do arquivo enviado não está entre as aceitas. |
| 401 | unauthorized | Não | Falta a credencial, ou ela é inválida, expirou ou foi revogada. Também vale para token de upload inválido ou expirado. |
| 403 | insufficient_scope | Não | O token OAuth não tem o escopo necessário: transcriptions:read ou transcriptions:write. |
| 403 | email_not_verified | Não | Você precisa confirmar o e-mail antes de criar uma transcrição. |
| 402 | insufficient_minutes | Não | O saldo disponível é 0 ou não cobre a duração da transcrição. |
| 402 | no_active_plan | Não | A 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. |
| 404 | not_found | Não | Essa transcrição não existe ou é de outra equipe. |
| 409 | upload_incomplete | Não | Ainda faltam partes do arquivo. Envie o que falta e peça a conclusão do upload novamente. |
| 409 | invalid_state | Não | A transcrição já saiu da etapa de espera pelo upload. Não é mais possível enviar partes ou concluir o envio. |
| 409 | idempotency_conflict | Não | Você já usou esse Idempotency-Key com outros parâmetros. |
| 413 | media_too_large | Não | O tamanho do arquivo ultrapassa o seu limite. Confira Uploads. |
| 413 | invalid_request | Não | O corpo JSON ultrapassa 1 MB. Para arquivos grandes, o código é media_too_large. |
| 429 | rate_limited | Sim | Você atingiu o limite de chamadas por minuto. Aguarde o número de segundos de Retry-After. |
| 429 | too_many_active_jobs | Sim | Você atingiu o limite de transcrições em andamento ou de uploads abertos. Aguarde o número de segundos de Retry-After. |
| 500 | internal_error | Sim | Tivemos um erro interno. Aguarde um pouco e tente novamente. |
| 503 | service_unavailable | Sim | O 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
retryablefortrue. Isso vale pararate_limited,too_many_active_jobs,internal_erroreservice_unavailable. - Respeite a espera de
Retry-Afterquando ele vier na resposta. Sem esse cabeçalho, aumente o intervalo a cada tentativa. - Para repetir
POST /v1/transcriptions, mantenha o mesmoIdempotency-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.code | O que aconteceu | Vale tentar novamente? |
|---|---|---|
media_unavailable | O vídeo não existe ou saiu do ar. | Não. Confira o link. |
media_private | O vídeo é privado. | Não. Envie um post público ou um vídeo do YouTube público ou não listado. |
login_required | A plataforma só libera o conteúdo após login. | Não. O serviço não repete essa tentativa. |
no_audio | Não há faixa de áudio no vídeo. | Não. O serviço não repete essa tentativa. |
age_restricted | O acesso ao vídeo tem restrição de idade. | Não pelo link. Envie o arquivo por upload. |
live_stream | A transmissão está ao vivo ou ainda não começou. | Espere a transmissão terminar. |
no_captions | Você escolheu captions em source, mas não há uma faixa de legendas que possa ser usada. | Troque para source: "auto" ou "stt". |
media_too_long | A gravação ultrapassa o limite de 5 horas do speech-to-text. | Divida a gravação antes de enviar. |
unsupported_media | Não foi possível ler o arquivo, ou ele não tem faixa de áudio. | Envie outro arquivo em um formato aceito. |
no_speech | Nenhuma fala detectada. | Não. |
unsupported_language | O serviço não aceita o idioma da gravação. | Corrija language para um código aceito ou "auto". |
insufficient_minutes | O saldo acabou antes de cobrarmos a transcrição. | Faça uma recarga antes de tentar. |
fetch_failed | Não conseguimos baixar o áudio ou vídeo, mesmo após várias tentativas. | Sim. Tente mais tarde. |
transcription_failed | A 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
{
"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 permitidos
transcription - statusstringobrigatório
Valores permitidos
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - sourceobjectobrigatório
Expandir atributosRecolher atributos
With
url- platformstringobrigatório
- urlstringobrigatórioaceita null
- media_idstringobrigatórioaceita null
With
filename- platformstringobrigatório
Valores permitidos
upload - filenamestringobrigatórioaceita null
- sizenumberobrigatórioaceita null
- mediaobjectobrigatórioaceita null
Expandir atributosRecolher atributos
- titlestringopcionalaceita null
- authorstringopcionalaceita null
- author_urlstringopcionalaceita null
- thumbnail_urlstringopcionalaceita null
- filenamestringopcional
- mime_typestringopcional
- sizenumberopcional
- duration_secondsnumberopcionalaceita null
- optionsobjectobrigatório
Expandir atributosRecolher atributos
- sourcestringobrigatório
Valores permitidos
autocaptionsstt - languagestringobrigatório
- diarizebooleanobrigatório
- transcript_sourcestringobrigatórioaceita null
Valores permitidos
youtube_captionsx_captionsspeech_to_text - caption_kindstringobrigatórioaceita null
Valores permitidos
manualauto_generated - languagestringobrigatórioaceita null
- billed_minutesintegerobrigatórioaceita null
- cachedbooleanobrigatório
- errorobjectobrigatórioaceita null
Expandir atributosRecolher 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
nullunless the request includesinclude_deleted=true. - transcriptobjectopcional
Included in
GETresponses for completed transcriptions.Expandir atributosRecolher atributos
- textstringobrigatório
- speakersarray of stringsobrigatório
- segmentsarray of objectsobrigatório
Expandir atributosRecolher atributos
- startnumberobrigatório
- endnumberobrigatório
- speakerstringobrigatórioaceita null
- languagestringobrigatórioaceita null
- textstringobrigatório
- wordsarray of objectsopcionalaceita null
Expandir atributosRecolher 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/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
}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 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.Valores permitidos
truefalse
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 permitidos
youtubextiktokinstagramfacebookblueskytwitchdailymotionpinterestlinkedinsnapchat - 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 permitidos
autocaptionsstt - languagestringopcional
- diarizebooleanopcional
- webhook_urlstring · uriopcional
With upload
- uploadobjectobrigatório
Expandir atributosRecolher atributos
- filenamestringobrigatório
- sizeintegerobrigatório
- mime_typestringopcional
- sourcestringopcional
Valores permitidos
autostt - languagestringopcional
- diarizebooleanopcional
- webhook_urlstring · uriopcional
multipart/form-data
- filestring · binaryobrigatório
- sourcestringopcional
Valores permitidos
autostt - languagestringopcional
- diarizebooleanopcional
- webhook_urlstring · uriopcional
Retorna
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
Outros códigos de status
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."
}
]
}
}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 permitidos
jsontextsrtvtt - includestringopcional
Valores permitidos
words - timestampsstringopcionalValor padrão: false
Valores permitidos
truefalse - include_deletedstringopcionalValor padrão: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valores permitidos
truefalse
Retorna
200 OK— The transcription, or the rendered transcript202 Accepted— A rendered format was requested while the transcription is still processing
Outros códigos de status
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"
}Query
- limitintegeropcionalValor padrão: 20
- cursorstringopcional
- statusstringopcional
Valores permitidos
awaiting_uploadqueuedfetchingtranscribingcompletedfailedcanceled - platformstringopcional
- include_deletedstringopcionalValor padrão: false
Also returns deleted transcriptions as read-only records without a transcript. Their
deleted_atis set. Defaults tofalse.Valores permitidos
truefalse
Retorna
200 OK— A page of transcriptions
Outros códigos de status
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"Resposta sem corpo
Path
- idstringobrigatório
Retorna
204 No Content— Canceled or deleted
Outros códigos de status
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
}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 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"
}Path
- idstringobrigatório
Retorna
200 OK— Upload progress
Outros códigos de status
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
}Path
- idstringobrigatório
Retorna
202 Accepted— The transcription is queued
Outros códigos de status
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
}
}Retorna
200 OK— The authenticated user's account
Outros códigos de status
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.
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 permitidos
account - userobjectobrigatório
Expandir atributosRecolher atributos
- idstringobrigatório
- emailstringobrigatório
- planobjectobrigatórioaceita null
Expandir atributosRecolher atributos
- idstringobrigatório
- namestringobrigatório
- minutesobjectobrigatório
Expandir atributosRecolher 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 atributosRecolher 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));
};{
"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
type | Quando você recebe |
|---|---|
transcription.completed | O status muda para completed. |
transcription.failed | O 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_atinforma quando o evento foi criado.datatraz o objeto da transcrição, mas sem o campotranscript.
Para buscar o texto, use o id de data em GET /v1/transcriptions/:id.
Também enviamos estes cabeçalhos:
Content-Type: application/jsonUser-Agent: transcript1-webhooks/1.0X-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>.
tinforma quando assinamos a requisição, em segundos Unix.v1contém o HMAC-SHA256 em hexadecimal da string"<t>.<raw body>". Monte essa string com o valor det, um ponto e o corpo exatamente como chegou. Use o segredo de assinatura inteiro como chave, com o prefixowhsec_.
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
tmuito 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 emraw_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
2xxpara 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
3xxuma falha de entrega. - Seu servidor pode receber o mesmo aviso mais de uma vez, por exemplo se responder depois do timeout. Confira
data.idetypepara não processar duplicatas.